]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 13 Oct 2008 17:07:53 +0000 (10:07 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 13 Oct 2008 17:07:53 +0000 (10:07 -0700)
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-2.6:
  chmc: Mark %ver register inline asm with __volatile__
  sparc64: Add missing notify_cpu_starting() call.
  sparc32: fix build errors

338 files changed:
Documentation/00-INDEX
Documentation/feature-removal-schedule.txt
Documentation/filesystems/proc.txt
Documentation/timers/00-INDEX [new file with mode: 0644]
Documentation/timers/hpet.txt [moved from Documentation/hpet.txt with 81% similarity]
MAINTAINERS
arch/Kconfig
arch/alpha/Kconfig
arch/alpha/include/asm/statfs.h
arch/arm/Kconfig
arch/arm/include/asm/statfs.h
arch/arm/kernel/dma.c
arch/avr32/include/asm/a.out.h [deleted file]
arch/blackfin/include/asm/a.out.h [deleted file]
arch/blackfin/kernel/bfin_dma_5xx.c
arch/blackfin/mach-bf527/include/mach/bfin_serial_5xx.h
arch/blackfin/mach-bf533/include/mach/bfin_serial_5xx.h
arch/blackfin/mach-bf537/include/mach/bfin_serial_5xx.h
arch/blackfin/mach-bf548/include/mach/bfin_serial_5xx.h
arch/blackfin/mach-bf561/include/mach/bfin_serial_5xx.h
arch/cris/arch-v10/boot/tools/build.c
arch/h8300/Kconfig
arch/h8300/include/asm/a.out.h [deleted file]
arch/h8300/kernel/process.c
arch/ia64/include/asm/a.out.h [deleted file]
arch/ia64/include/asm/statfs.h
arch/ia64/mm/init.c
arch/m32r/Kconfig
arch/m68k/Kconfig
arch/m68knommu/Kconfig
arch/m68knommu/include/asm/a.out.h [deleted file]
arch/m68knommu/kernel/process.c
arch/m68knommu/kernel/traps.c
arch/mips/include/asm/a.out.h [deleted file]
arch/mips/kernel/process.c
arch/mips/kernel/syscall.c
arch/mn10300/Kconfig
arch/parisc/Kconfig
arch/powerpc/include/asm/a.out.h [deleted file]
arch/powerpc/include/asm/statfs.h
arch/powerpc/kernel/softemu8xx.c
arch/powerpc/kernel/traps.c
arch/powerpc/platforms/chrp/setup.c
arch/powerpc/platforms/maple/setup.c
arch/powerpc/platforms/powermac/setup.c
arch/powerpc/platforms/pseries/setup.c
arch/s390/include/asm/statfs.h
arch/sparc/include/asm/Kbuild
arch/sparc/include/asm/serial.h [new file with mode: 0644]
arch/sparc/include/asm/statfs.h
arch/sparc/include/asm/statfs_32.h [deleted file]
arch/sparc/include/asm/statfs_64.h [deleted file]
arch/um/Kconfig.i386
arch/um/Kconfig.x86_64
arch/um/drivers/line.c
arch/x86/Kconfig
arch/x86/Kconfig.cpu
arch/x86/Makefile_32.cpu
arch/x86/configs/i386_defconfig
arch/x86/configs/x86_64_defconfig
arch/x86/ia32/ia32entry.S
arch/x86/kernel/Makefile
arch/x86/kernel/alternative.c
arch/x86/kernel/apic_32.c
arch/x86/kernel/apic_64.c
arch/x86/kernel/cpu/common.c
arch/x86/kernel/doublefault_32.c
arch/x86/kernel/dumpstack_32.c [new file with mode: 0644]
arch/x86/kernel/dumpstack_64.c [new file with mode: 0644]
arch/x86/kernel/entry_32.S
arch/x86/kernel/entry_64.S
arch/x86/kernel/es7000_32.c
arch/x86/kernel/genx2apic_uv_x.c
arch/x86/kernel/head.c
arch/x86/kernel/hpet.c
arch/x86/kernel/irqinit_64.c
arch/x86/kernel/process_32.c
arch/x86/kernel/process_64.c
arch/x86/kernel/quirks.c
arch/x86/kernel/setup.c
arch/x86/kernel/smpboot.c
arch/x86/kernel/time_32.c
arch/x86/kernel/time_64.c
arch/x86/kernel/traps.c [moved from arch/x86/kernel/traps_32.c with 57% similarity]
arch/x86/kernel/traps_64.c [deleted file]
arch/x86/mach-generic/es7000.c
arch/x86/mm/Makefile
arch/x86/mm/fault.c
arch/x86/mm/gup.c
arch/x86/mm/init_32.c
arch/x86/mm/init_64.c
arch/x86/mm/ioremap.c
arch/x86/mm/numa_32.c [moved from arch/x86/mm/discontig_32.c with 100% similarity]
arch/x86/mm/srat_64.c
arch/x86/oprofile/Makefile
arch/x86/oprofile/nmi_int.c
arch/x86/oprofile/op_model_amd.c [new file with mode: 0644]
arch/x86/oprofile/op_model_athlon.c [deleted file]
arch/x86/oprofile/op_x86_model.h
arch/x86/pci/fixup.c
drivers/bluetooth/hci_ldisc.c
drivers/char/Kconfig
drivers/char/Makefile
drivers/char/amiserial.c
drivers/char/applicom.c
drivers/char/cyclades.c
drivers/char/epca.c
drivers/char/generic_serial.c
drivers/char/hpet.c
drivers/char/hvc_console.c
drivers/char/ip2/Makefile
drivers/char/ip2/i2ellis.c
drivers/char/ip2/i2ellis.h
drivers/char/ip2/ip2base.c [deleted file]
drivers/char/ip2/ip2main.c
drivers/char/isicom.c
drivers/char/istallion.c
drivers/char/moxa.c
drivers/char/mxser.c
drivers/char/n_hdlc.c
drivers/char/n_r3964.c
drivers/char/n_tty.c
drivers/char/nozomi.c
drivers/char/pcmcia/ipwireless/tty.c
drivers/char/pty.c
drivers/char/stallion.c
drivers/char/sx.c
drivers/char/tpm/tpm.c
drivers/char/tpm/tpm.h
drivers/char/tpm/tpm_tis.c
drivers/char/tty_audit.c
drivers/char/tty_buffer.c [new file with mode: 0644]
drivers/char/tty_io.c
drivers/char/tty_ioctl.c
drivers/char/tty_port.c [new file with mode: 0644]
drivers/char/vt.c
drivers/char/vt_ioctl.c
drivers/isdn/capi/capi.c
drivers/isdn/gigaset/ser-gigaset.c
drivers/media/video/cafe_ccic.c
drivers/mmc/host/sdhci-pci.c
drivers/mtd/nand/cafe_nand.c
drivers/net/wan/Kconfig
drivers/oprofile/buffer_sync.c
drivers/oprofile/cpu_buffer.c
drivers/oprofile/cpu_buffer.h
drivers/s390/char/fs3270.c
drivers/serial/8250.c
drivers/serial/8250_pci.c
drivers/serial/Kconfig
drivers/serial/Makefile
drivers/serial/bfin_5xx.c
drivers/serial/crisv10.c
drivers/serial/mcfserial.c [deleted file]
drivers/serial/mcfserial.h [deleted file]
drivers/serial/serial_core.c
drivers/usb/serial/aircable.c
drivers/usb/serial/belkin_sa.c
drivers/usb/serial/console.c
drivers/usb/serial/cyberjack.c
drivers/usb/serial/cypress_m8.c
drivers/usb/serial/digi_acceleport.c
drivers/usb/serial/empeg.c
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/garmin_gps.c
drivers/usb/serial/generic.c
drivers/usb/serial/io_edgeport.c
drivers/usb/serial/io_ti.c
drivers/usb/serial/ipaq.c
drivers/usb/serial/ipw.c
drivers/usb/serial/ir-usb.c
drivers/usb/serial/iuu_phoenix.c
drivers/usb/serial/keyspan.c
drivers/usb/serial/keyspan_pda.c
drivers/usb/serial/kl5kusb105.c
drivers/usb/serial/kobil_sct.c
drivers/usb/serial/mct_u232.c
drivers/usb/serial/mos7720.c
drivers/usb/serial/mos7840.c
drivers/usb/serial/navman.c
drivers/usb/serial/omninet.c
drivers/usb/serial/option.c
drivers/usb/serial/oti6858.c
drivers/usb/serial/pl2303.c
drivers/usb/serial/safe_serial.c
drivers/usb/serial/sierra.c
drivers/usb/serial/spcp8x5.c
drivers/usb/serial/ti_usb_3410_5052.c
drivers/usb/serial/usb-serial.c
drivers/usb/serial/visor.c
drivers/usb/serial/whiteheat.c
drivers/video/backlight/mbp_nvidia_bl.c
fs/Kconfig.binfmt
fs/debugfs/inode.c
fs/devpts/inode.c
fs/dquot.c
fs/efs/super.c
fs/open.c
fs/proc/Kconfig
fs/proc/array.c
fs/proc/base.c
fs/proc/inode.c
fs/proc/internal.h
fs/proc/proc_misc.c
fs/proc/proc_sysctl.c
fs/proc/task_mmu.c
fs/proc/task_nommu.c
fs/proc/vmcore.c
include/asm-cris/a.out.h [deleted file]
include/asm-generic/statfs.h
include/asm-m32r/a.out.h [deleted file]
include/asm-parisc/a.out.h [deleted file]
include/asm-parisc/statfs.h
include/asm-x86/desc.h
include/asm-x86/es7000/mpparse.h
include/asm-x86/fixmap_32.h
include/asm-x86/fixmap_64.h
include/asm-x86/io.h
include/asm-x86/io_64.h
include/asm-x86/ioctls.h
include/asm-x86/irqflags.h
include/asm-x86/kdebug.h
include/asm-x86/kprobes.h
include/asm-x86/mach-default/mach_traps.h
include/asm-x86/module.h
include/asm-x86/nmi.h
include/asm-x86/page.h
include/asm-x86/page_32.h
include/asm-x86/pgtable.h
include/asm-x86/ptrace.h
include/asm-x86/segment.h
include/asm-x86/smp.h
include/asm-x86/statfs.h
include/asm-x86/system.h
include/asm-x86/traps.h
include/asm-xtensa/a.out.h [deleted file]
include/linux/devpts_fs.h
include/linux/dmi.h
include/linux/hpet.h
include/linux/magic.h
include/linux/mod_devicetable.h
include/linux/oprofile.h
include/linux/pci_ids.h
include/linux/serial.h
include/linux/serial_core.h
include/linux/termios.h
include/linux/tty.h
include/linux/tty_driver.h
include/linux/vt_kern.h
include/net/cipso_ipv4.h
include/net/netlabel.h
include/sound/soc-dapm.h
init/Kconfig
kernel/acct.c
kernel/auditsc.c
kernel/fork.c
kernel/printk.c
kernel/sched_debug.c
kernel/sys.c
kernel/sysctl.c
mm/shmem.c
net/ipv4/cipso_ipv4.c
net/ipv4/ip_options.c
net/netlabel/Makefile
net/netlabel/netlabel_addrlist.c [new file with mode: 0644]
net/netlabel/netlabel_addrlist.h [new file with mode: 0644]
net/netlabel/netlabel_cipso_v4.c
net/netlabel/netlabel_cipso_v4.h
net/netlabel/netlabel_domainhash.c
net/netlabel/netlabel_domainhash.h
net/netlabel/netlabel_kapi.c
net/netlabel/netlabel_mgmt.c
net/netlabel/netlabel_mgmt.h
net/netlabel/netlabel_unlabeled.c
scripts/mod/file2alias.c
security/inode.c
security/selinux/hooks.c
security/selinux/include/netlabel.h
security/selinux/include/objsec.h
security/selinux/netlabel.c
security/selinux/ss/services.c
security/smack/smack_lsm.c
security/smack/smackfs.c
sound/oss/ac97_codec.c
sound/pci/ac97/ac97_patch.c
sound/pci/hda/patch_sigmatel.c
sound/soc/at91/Kconfig
sound/soc/at91/Makefile
sound/soc/at91/at91-ssc.c
sound/soc/at91/eti_b1_wm8731.c [deleted file]
sound/soc/blackfin/Kconfig
sound/soc/blackfin/Makefile
sound/soc/blackfin/bf5xx-ac97-pcm.c
sound/soc/blackfin/bf5xx-ac97.c
sound/soc/blackfin/bf5xx-ad73311.c [new file with mode: 0644]
sound/soc/blackfin/bf5xx-i2s.c
sound/soc/blackfin/bf5xx-sport.h
sound/soc/codecs/Kconfig
sound/soc/codecs/Makefile
sound/soc/codecs/ac97.c
sound/soc/codecs/ad1980.c
sound/soc/codecs/ad73311.c [new file with mode: 0644]
sound/soc/codecs/ad73311.h [new file with mode: 0644]
sound/soc/codecs/ak4535.c
sound/soc/codecs/ssm2602.c
sound/soc/codecs/tlv320aic23.c [new file with mode: 0644]
sound/soc/codecs/tlv320aic23.h [new file with mode: 0644]
sound/soc/codecs/tlv320aic3x.c
sound/soc/codecs/uda1380.c
sound/soc/codecs/wm8510.c
sound/soc/codecs/wm8510.h
sound/soc/codecs/wm8580.c
sound/soc/codecs/wm8731.c
sound/soc/codecs/wm8750.c
sound/soc/codecs/wm8753.c
sound/soc/codecs/wm8753.h
sound/soc/codecs/wm8900.c
sound/soc/codecs/wm8903.c
sound/soc/codecs/wm8971.c
sound/soc/codecs/wm8990.c
sound/soc/codecs/wm9712.c
sound/soc/codecs/wm9713.c
sound/soc/omap/Kconfig
sound/soc/omap/Makefile
sound/soc/omap/n810.c
sound/soc/omap/omap-mcbsp.c
sound/soc/omap/omap-mcbsp.h
sound/soc/omap/omap-pcm.c
sound/soc/omap/osk5912.c [new file with mode: 0644]
sound/soc/pxa/corgi.c
sound/soc/pxa/em-x270.c
sound/soc/pxa/poodle.c
sound/soc/pxa/pxa2xx-i2s.c
sound/soc/pxa/spitz.c
sound/soc/pxa/tosa.c
sound/soc/s3c24xx/neo1973_wm8753.c
sound/soc/soc-core.c
sound/soc/soc-dapm.c

index 73060819ed99c6889c716cf922e1997f37f4a0b0..4382778001039c7fc6595f7659895a7301533ba8 100644 (file)
@@ -159,8 +159,6 @@ hayes-esp.txt
        - info on using the Hayes ESP serial driver.
 highuid.txt
        - notes on the change from 16 bit to 32 bit user/group IDs.
-hpet.txt
-       - High Precision Event Timer Driver for Linux.
 timers/
        - info on the timer related topics
 hw_random.txt
index 3d2d0c29f02735e01e1acbc3bf3d1c97440352f2..cc8093c15cf5ce4c063aed880acfce7555903986 100644 (file)
@@ -287,14 +287,6 @@ Who:       Glauber Costa <gcosta@redhat.com>
 
 ---------------------------
 
-What:  old style serial driver for ColdFire (CONFIG_SERIAL_COLDFIRE)
-When:  2.6.28
-Why:   This driver still uses the old interface and has been replaced
-       by CONFIG_SERIAL_MCF.
-Who:   Sebastian Siewior <sebastian@breakpoint.cc>
-
----------------------------
-
 What:  /sys/o2cb symlink
 When:  January 2010
 Why:   /sys/fs/o2cb is the proper location for this information - /sys/o2cb
index d831d24d2a6c133214ad3663f1d7762138e3dbe4..b488edad743cef9c5d8fea84ab1dcb491aa38c87 100644 (file)
@@ -1331,13 +1331,6 @@ determine whether or not they are still functioning properly.
 Because the NMI watchdog shares registers with oprofile, by disabling the NMI
 watchdog, oprofile may have more registers to utilize.
 
-maps_protect
-------------
-
-Enables/Disables the protection of the per-process proc entries "maps" and
-"smaps".  When enabled, the contents of these files are visible only to
-readers that are allowed to ptrace() the given process.
-
 msgmni
 ------
 
diff --git a/Documentation/timers/00-INDEX b/Documentation/timers/00-INDEX
new file mode 100644 (file)
index 0000000..397dc35
--- /dev/null
@@ -0,0 +1,10 @@
+00-INDEX
+       - this file
+highres.txt
+       - High resolution timers and dynamic ticks design notes
+hpet.txt
+       - High Precision Event Timer Driver for Linux
+hrtimers.txt
+       - subsystem for high-resolution kernel timers
+timer_stats.txt
+       - timer usage statistics
similarity index 81%
rename from Documentation/hpet.txt
rename to Documentation/timers/hpet.txt
index 6ad52d9dad6cab36b4fac984aa3f39b3aba073fe..e7c09abcfab424d12f9628e06d594327cf475c93 100644 (file)
@@ -1,21 +1,32 @@
                High Precision Event Timer Driver for Linux
 
-The High Precision Event Timer (HPET) hardware is the future replacement
-for the 8254 and Real Time Clock (RTC) periodic timer functionality.
-Each HPET can have up to 32 timers.  It is possible to configure the
-first two timers as legacy replacements for 8254 and RTC periodic timers.
-A specification done by Intel and Microsoft can be found at
-<http://www.intel.com/technology/architecture/hpetspec.htm>.
+The High Precision Event Timer (HPET) hardware follows a specification
+by Intel and Microsoft which can be found at
+
+       http://www.intel.com/technology/architecture/hpetspec.htm
+
+Each HPET has one fixed-rate counter (at 10+ MHz, hence "High Precision")
+and up to 32 comparators.  Normally three or more comparators are provided,
+each of which can generate oneshot interupts and at least one of which has
+additional hardware to support periodic interrupts.  The comparators are
+also called "timers", which can be misleading since usually timers are
+independent of each other ... these share a counter, complicating resets.
+
+HPET devices can support two interrupt routing modes.  In one mode, the
+comparators are additional interrupt sources with no particular system
+role.  Many x86 BIOS writers don't route HPET interrupts at all, which
+prevents use of that mode.  They support the other "legacy replacement"
+mode where the first two comparators block interrupts from 8254 timers
+and from the RTC.
 
 The driver supports detection of HPET driver allocation and initialization
 of the HPET before the driver module_init routine is called.  This enables
 platform code which uses timer 0 or 1 as the main timer to intercept HPET
 initialization.  An example of this initialization can be found in
-arch/i386/kernel/time_hpet.c.
+arch/x86/kernel/hpet.c.
 
-The driver provides two APIs which are very similar to the API found in
-the rtc.c driver.  There is a user space API and a kernel space API.
-An example user space program is provided below.
+The driver provides a userspace API which resembles the API found in the
+RTC driver framework.  An example user space program is provided below.
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -286,15 +297,3 @@ out:
 
        return;
 }
-
-The kernel API has three interfaces exported from the driver:
-
-       hpet_register(struct hpet_task *tp, int periodic)
-       hpet_unregister(struct hpet_task *tp)
-       hpet_control(struct hpet_task *tp, unsigned int cmd, unsigned long arg)
-
-The kernel module using this interface fills in the ht_func and ht_data
-members of the hpet_task structure before calling hpet_register.
-hpet_control simply vectors to the hpet_ioctl routine and has the same
-commands and respective arguments as the user API.  hpet_unregister
-is used to terminate usage of the HPET timer reserved by hpet_register.
index 6ba3ee822838cea89be914acb2333424ec644c9d..74b80820531203f96f51c6ed3c5327f18df5f609 100644 (file)
@@ -2797,15 +2797,6 @@ L:       linux-mtd@lists.infradead.org
 T:     git git://git.infradead.org/mtd-2.6.git
 S:     Maintained
 
-MEI MN10300/AM33 PORT
-P:     David Howells
-M:     dhowells@redhat.com
-P:     Koichi Yasutake
-M:     yasutake.koichi@jp.panasonic.com
-L:     linux-am33-list@redhat.com (moderated for non-subscribers)
-W:     ftp://ftp.redhat.com/pub/redhat/gnupro/AM33/
-S:     Maintained
-
 MICROTEK X6 SCANNER
 P:     Oliver Neukum
 M:     oliver@neukum.name
@@ -3170,6 +3161,15 @@ M:       olof@lixom.net
 L:     i2c@lm-sensors.org
 S:     Maintained
 
+PANASONIC MN10300/AM33 PORT
+P:     David Howells
+M:     dhowells@redhat.com
+P:     Koichi Yasutake
+M:     yasutake.koichi@jp.panasonic.com
+L:     linux-am33-list@redhat.com (moderated for non-subscribers)
+W:     ftp://ftp.redhat.com/pub/redhat/gnupro/AM33/
+S:     Maintained
+
 PARALLEL PORT SUPPORT
 L:     linux-parport@lists.infradead.org (subscribers-only)
 S:     Orphan
index 364c6dadde0a6b6ed988f15294f799240b292a68..0267babe5eb9dc6a6c79f2347234b7d78aafc2e8 100644 (file)
@@ -13,6 +13,20 @@ config OPROFILE
 
          If unsure, say N.
 
+config OPROFILE_IBS
+       bool "OProfile AMD IBS support (EXPERIMENTAL)"
+       default n
+       depends on OPROFILE && SMP && X86
+       help
+          Instruction-Based Sampling (IBS) is a new profiling
+          technique that provides rich, precise program performance
+          information. IBS is introduced by AMD Family10h processors
+          (AMD Opteron Quad-Core processor “Barcelona”) to overcome
+          the limitations of conventional performance counter
+          sampling.
+
+         If unsure, say N.
+
 config HAVE_OPROFILE
        def_bool n
 
index 1bec55d63ef6241fb9451c821a09960657503acb..ee35226c44e94ff7fcedb0157016af8c4d08f781 100644 (file)
@@ -5,6 +5,7 @@
 config ALPHA
        bool
        default y
+       select HAVE_AOUT
        select HAVE_IDE
        select HAVE_OPROFILE
        help
@@ -68,9 +69,6 @@ config AUTO_IRQ_AFFINITY
        depends on SMP
        default y
 
-config ARCH_SUPPORTS_AOUT
-       def_bool y
-
 source "init/Kconfig"
 
 
index ad15830baefe43199b00d5fc88e445b96b59031b..de35cd438a1023a57f3c5dfb4a49230d8ff69aee 100644 (file)
@@ -1,6 +1,10 @@
 #ifndef _ALPHA_STATFS_H
 #define _ALPHA_STATFS_H
 
+/* Alpha is the only 64-bit platform with 32-bit statfs. And doesn't
+   even seem to implement statfs64 */
+#define __statfs_word __u32
+
 #include <asm-generic/statfs.h>
 
 #endif
index efeed65b4a66616d5fae54b35fbd0947735359ac..4853f9df37bd22a037f122bd7d78a9a6600cc474 100644 (file)
@@ -8,6 +8,7 @@ mainmenu "Linux Kernel Configuration"
 config ARM
        bool
        default y
+       select HAVE_AOUT
        select HAVE_IDE
        select RTC_LIB
        select SYS_SUPPORTS_APM_EMULATION
@@ -140,9 +141,6 @@ config GENERIC_CALIBRATE_DELAY
        bool
        default y
 
-config ARCH_SUPPORTS_AOUT
-       def_bool y
-
 config ARCH_MAY_HAVE_PC_FDC
        bool
 
index a02e6a8c3d70ac2d681ef9dd35a426426f1b0ae4..079447c05ba7ea9ea970fee600f03a863e7eaebd 100644 (file)
@@ -1,42 +1,12 @@
 #ifndef _ASMARM_STATFS_H
 #define _ASMARM_STATFS_H
 
-#ifndef __KERNEL_STRICT_NAMES
-# include <linux/types.h>
-typedef __kernel_fsid_t        fsid_t;
-#endif
-
-struct statfs {
-       __u32 f_type;
-       __u32 f_bsize;
-       __u32 f_blocks;
-       __u32 f_bfree;
-       __u32 f_bavail;
-       __u32 f_files;
-       __u32 f_ffree;
-       __kernel_fsid_t f_fsid;
-       __u32 f_namelen;
-       __u32 f_frsize;
-       __u32 f_spare[5];
-};
-
 /*
  * With EABI there is 4 bytes of padding added to this structure.
  * Let's pack it so the padding goes away to simplify dual ABI support.
  * Note that user space does NOT have to pack this structure.
  */
-struct statfs64 {
-       __u32 f_type;
-       __u32 f_bsize;
-       __u64 f_blocks;
-       __u64 f_bfree;
-       __u64 f_bavail;
-       __u64 f_files;
-       __u64 f_ffree;
-       __kernel_fsid_t f_fsid;
-       __u32 f_namelen;
-       __u32 f_frsize;
-       __u32 f_spare[5];
-} __attribute__ ((packed,aligned(4)));
+#define ARCH_PACK_STATFS64 __attribute__((packed,aligned(4)))
 
+#include <asm-generic/statfs.h>
 #endif
index ba99a20355236a06491922a63e0ef745f0bcfcc5..d006085ed7e7b882966510d09695fbb4b1a6091a 100644 (file)
@@ -25,23 +25,6 @@ EXPORT_SYMBOL(dma_spin_lock);
 
 static dma_t dma_chan[MAX_DMA_CHANNELS];
 
-/*
- * Get dma list for /proc/dma
- */
-int get_dma_list(char *buf)
-{
-       dma_t *dma;
-       char *p = buf;
-       int i;
-
-       for (i = 0, dma = dma_chan; i < MAX_DMA_CHANNELS; i++, dma++)
-               if (dma->lock)
-                       p += sprintf(p, "%2d: %14s %s\n", i,
-                                    dma->d_ops->type, dma->device_id);
-
-       return p - buf;
-}
-
 /*
  * Request DMA channel
  *
diff --git a/arch/avr32/include/asm/a.out.h b/arch/avr32/include/asm/a.out.h
deleted file mode 100644 (file)
index e46375a..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef __ASM_AVR32_A_OUT_H
-#define __ASM_AVR32_A_OUT_H
-
-struct exec
-{
-  unsigned long a_info;                /* Use macros N_MAGIC, etc for access */
-  unsigned a_text;             /* length of text, in bytes */
-  unsigned a_data;             /* length of data, in bytes */
-  unsigned a_bss;              /* length of uninitialized data area for file, in bytes */
-  unsigned a_syms;             /* length of symbol table data in file, in bytes */
-  unsigned a_entry;            /* start address */
-  unsigned a_trsize;           /* length of relocation info for text, in bytes */
-  unsigned a_drsize;           /* length of relocation info for data, in bytes */
-};
-
-#define N_TRSIZE(a)    ((a).a_trsize)
-#define N_DRSIZE(a)    ((a).a_drsize)
-#define N_SYMSIZE(a)   ((a).a_syms)
-
-#endif /* __ASM_AVR32_A_OUT_H */
diff --git a/arch/blackfin/include/asm/a.out.h b/arch/blackfin/include/asm/a.out.h
deleted file mode 100644 (file)
index 6c3d652..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-#ifndef __BFIN_A_OUT_H__
-#define __BFIN_A_OUT_H__
-
-struct exec {
-       unsigned long a_info;   /* Use macros N_MAGIC, etc for access */
-       unsigned a_text;        /* length of text, in bytes */
-       unsigned a_data;        /* length of data, in bytes */
-       unsigned a_bss;         /* length of uninitialized data area for file, in bytes */
-       unsigned a_syms;        /* length of symbol table data in file, in bytes */
-       unsigned a_entry;       /* start address */
-       unsigned a_trsize;      /* length of relocation info for text, in bytes */
-       unsigned a_drsize;      /* length of relocation info for data, in bytes */
-};
-
-#define N_TRSIZE(a)    ((a).a_trsize)
-#define N_DRSIZE(a)    ((a).a_drsize)
-#define N_SYMSIZE(a)   ((a).a_syms)
-
-#endif                         /* __BFIN_A_OUT_H__ */
index 93229b3d6e3e30da6bc17dd760bd48ddbacda0af..339293d677cc33608970e912476dad1040ab7ade 100644 (file)
@@ -117,15 +117,14 @@ int request_dma(unsigned int channel, char *device_id)
 
 #ifdef CONFIG_BF54x
        if (channel >= CH_UART2_RX && channel <= CH_UART3_TX) {
-               if (strncmp(device_id, "BFIN_UART", 9) == 0) {
-                       dma_ch[channel].regs->peripheral_map &= 0x0FFF;
-                       dma_ch[channel].regs->peripheral_map |=
+               unsigned int per_map;
+               per_map = dma_ch[channel].regs->peripheral_map & 0xFFF;
+               if (strncmp(device_id, "BFIN_UART", 9) == 0)
+                       dma_ch[channel].regs->peripheral_map = per_map |
                                ((channel - CH_UART2_RX + 0xC)<<12);
-               } else {
-                       dma_ch[channel].regs->peripheral_map &= 0x0FFF;
-                       dma_ch[channel].regs->peripheral_map |=
+               else
+                       dma_ch[channel].regs->peripheral_map = per_map |
                                ((channel - CH_UART2_RX + 0x6)<<12);
-               }
        }
 #endif
 
index 2526b6ed6faa78ce72d45d9e210743c589850f8e..75722d6008b0cade6651e72911d7bfdb3543cbf6 100644 (file)
@@ -78,6 +78,9 @@
 #  define CONFIG_UART1_RTS_PIN -1
 # endif
 #endif
+
+#define BFIN_UART_TX_FIFO_SIZE 2
+
 /*
  * The pin configuration is different from schematic
  */
@@ -119,7 +122,6 @@ static inline void UART_CLEAR_LSR(struct bfin_serial_port *uart)
        bfin_write16(uart->port.membase + OFFSET_LSR, -1);
 }
 
-struct bfin_serial_port bfin_serial_ports[BFIN_UART_NR_PORTS];
 struct bfin_serial_res {
        unsigned long uart_base_addr;
        int uart_irq;
@@ -164,8 +166,6 @@ struct bfin_serial_res bfin_serial_resource[] = {
 #endif
 };
 
-int nr_ports = ARRAY_SIZE(bfin_serial_resource);
-
 #define DRIVER_NAME "bfin-uart"
 
 static void bfin_serial_hw_init(struct bfin_serial_port *uart)
index ebf592b59aab4b88a1d790f013f86535d55ccfeb..815bfe5dd1a99a74d06f1f86ef16c764ac990271 100644 (file)
@@ -69,6 +69,8 @@
 # endif
 #endif
 
+#define BFIN_UART_TX_FIFO_SIZE 2
+
 struct bfin_serial_port {
         struct uart_port        port;
         unsigned int            old_status;
@@ -111,7 +113,6 @@ static inline void UART_CLEAR_LSR(struct bfin_serial_port *uart)
        bfin_write16(uart->port.membase + OFFSET_LSR, -1);
 }
 
-struct bfin_serial_port bfin_serial_ports[BFIN_UART_NR_PORTS];
 struct bfin_serial_res {
        unsigned long   uart_base_addr;
        int             uart_irq;
@@ -142,7 +143,6 @@ struct bfin_serial_res bfin_serial_resource[] = {
 
 #define DRIVER_NAME "bfin-uart"
 
-int nr_ports = BFIN_UART_NR_PORTS;
 static void bfin_serial_hw_init(struct bfin_serial_port *uart)
 {
 
index 1bf56ffa22f946236dfcfad9d14b27db6e26d090..b3f87e1d16a2f5ffa18156b35e76edc01c451870 100644 (file)
@@ -78,6 +78,9 @@
 #  define CONFIG_UART1_RTS_PIN -1
 # endif
 #endif
+
+#define BFIN_UART_TX_FIFO_SIZE 2
+
 /*
  * The pin configuration is different from schematic
  */
@@ -119,7 +122,6 @@ static inline void UART_CLEAR_LSR(struct bfin_serial_port *uart)
        bfin_write16(uart->port.membase + OFFSET_LSR, -1);
 }
 
-struct bfin_serial_port bfin_serial_ports[BFIN_UART_NR_PORTS];
 struct bfin_serial_res {
        unsigned long   uart_base_addr;
        int             uart_irq;
@@ -164,8 +166,6 @@ struct bfin_serial_res bfin_serial_resource[] = {
 #endif
 };
 
-int nr_ports = ARRAY_SIZE(bfin_serial_resource);
-
 #define DRIVER_NAME "bfin-uart"
 
 static void bfin_serial_hw_init(struct bfin_serial_port *uart)
index 5e29446a8e03dde1acbf65bcc136a8cb83f5f60a..e4cf35e7ab9fd6c8a4adf80d10090e821a266ba3 100644 (file)
@@ -82,6 +82,9 @@
 #  define CONFIG_UART1_RTS_PIN -1
 # endif
 #endif
+
+#define BFIN_UART_TX_FIFO_SIZE 2
+
 /*
  * The pin configuration is different from schematic
  */
@@ -105,7 +108,6 @@ struct bfin_serial_port {
 #endif
 };
 
-struct bfin_serial_port bfin_serial_ports[BFIN_UART_NR_PORTS];
 struct bfin_serial_res {
        unsigned long   uart_base_addr;
        int             uart_irq;
@@ -170,8 +172,6 @@ struct bfin_serial_res bfin_serial_resource[] = {
 #endif
 };
 
-int nr_ports = ARRAY_SIZE(bfin_serial_resource);
-
 #define DRIVER_NAME "bfin-uart"
 
 static void bfin_serial_hw_init(struct bfin_serial_port *uart)
index 8aa02780e642ccde6deee3e79b4fe401d481902d..e0ce0c1843d458bb28b6ee6e53eb9e7747e2566b 100644 (file)
@@ -69,6 +69,8 @@
 # endif
 #endif
 
+#define BFIN_UART_TX_FIFO_SIZE 2
+
 struct bfin_serial_port {
         struct uart_port        port;
         unsigned int            old_status;
@@ -111,7 +113,6 @@ static inline void UART_CLEAR_LSR(struct bfin_serial_port *uart)
        bfin_write16(uart->port.membase + OFFSET_LSR, -1);
 }
 
-struct bfin_serial_port bfin_serial_ports[BFIN_UART_NR_PORTS];
 struct bfin_serial_res {
        unsigned long   uart_base_addr;
        int             uart_irq;
@@ -142,7 +143,6 @@ struct bfin_serial_res bfin_serial_resource[] = {
 
 #define DRIVER_NAME "bfin-uart"
 
-int nr_ports = BFIN_UART_NR_PORTS;
 static void bfin_serial_hw_init(struct bfin_serial_port *uart)
 {
 
index 2f9bbb26d6036960cc4be90a2bccfc50bb0330fd..c8adef364160daa8fedb6ac4af2049df263d6a87 100644 (file)
@@ -30,7 +30,6 @@
 #include <sys/sysmacros.h>
 #include <unistd.h>    /* contains read/write */
 #include <fcntl.h>
-#include <linux/a.out.h>
 #include <errno.h>
 
 #define MINIX_HEADER 32
index 396ab059efa35a9fa1d2e8258aff56cd0f8f0ab4..107cb5bb9f39f0b99a3ba2a0841d0a373a19dfbf 100644 (file)
@@ -66,9 +66,6 @@ config TIME_LOW_RES
        bool
        default y
 
-config ARCH_SUPPORTS_AOUT
-       def_bool y
-
 config NO_IOPORT
        def_bool y
 
diff --git a/arch/h8300/include/asm/a.out.h b/arch/h8300/include/asm/a.out.h
deleted file mode 100644 (file)
index ded780f..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef __H8300_A_OUT_H__
-#define __H8300_A_OUT_H__
-
-struct exec
-{
-  unsigned long a_info;                /* Use macros N_MAGIC, etc for access */
-  unsigned a_text;             /* length of text, in bytes */
-  unsigned a_data;             /* length of data, in bytes */
-  unsigned a_bss;              /* length of uninitialized data area for file, in bytes */
-  unsigned a_syms;             /* length of symbol table data in file, in bytes */
-  unsigned a_entry;            /* start address */
-  unsigned a_trsize;           /* length of relocation info for text, in bytes */
-  unsigned a_drsize;           /* length of relocation info for data, in bytes */
-};
-
-#define N_TRSIZE(a)    ((a).a_trsize)
-#define N_DRSIZE(a)    ((a).a_drsize)
-#define N_SYMSIZE(a)   ((a).a_syms)
-
-#endif /* __H8300_A_OUT_H__ */
index dfbe7ab9ffe2e2fa632260ccb2111d3a9e9a87df..a8ef654a5a0b8403af3a52c709478956140d2690 100644 (file)
@@ -34,7 +34,6 @@
 #include <linux/ptrace.h>
 #include <linux/slab.h>
 #include <linux/user.h>
-#include <linux/a.out.h>
 #include <linux/interrupt.h>
 #include <linux/reboot.h>
 #include <linux/fs.h>
diff --git a/arch/ia64/include/asm/a.out.h b/arch/ia64/include/asm/a.out.h
deleted file mode 100644 (file)
index 193dcfb..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-#ifndef _ASM_IA64_A_OUT_H
-#define _ASM_IA64_A_OUT_H
-
-/*
- * No a.out format has been (or should be) defined so this file is
- * just a dummy that allows us to get binfmt_elf compiled.  It
- * probably would be better to clean up binfmt_elf.c so it does not
- * necessarily depend on there being a.out support.
- *
- * Modified 1998-2002
- *     David Mosberger-Tang <davidm@hpl.hp.com>, Hewlett-Packard Co.
- */
-
-#include <linux/types.h>
-
-struct exec {
-       unsigned long a_info;
-       unsigned long a_text;
-       unsigned long a_data;
-       unsigned long a_bss;
-       unsigned long a_entry;
-};
-
-#define N_TXTADDR(x)   0
-#define N_DATADDR(x)   0
-#define N_BSSADDR(x)   0
-#define N_DRSIZE(x)    0
-#define N_TRSIZE(x)    0
-#define N_SYMSIZE(x)   0
-#define N_TXTOFF(x)    0
-
-#endif /* _ASM_IA64_A_OUT_H */
index 811097974f31ed54d281564134c648fb62e7ea59..1e589669de56fee4f2dd1c718efd2191776c5770 100644 (file)
@@ -8,55 +8,13 @@
  *     David Mosberger-Tang <davidm@hpl.hp.com>, Hewlett-Packard Co
  */
 
-#ifndef __KERNEL_STRICT_NAMES
-# include <linux/types.h>
-typedef __kernel_fsid_t        fsid_t;
-#endif
-
 /*
- * This is ugly --- we're already 64-bit, so just duplicate the definitions
+ * We need compat_statfs64 to be packed, because the i386 ABI won't
+ * add padding at the end to bring it to a multiple of 8 bytes, but
+ * the IA64 ABI will.
  */
-struct statfs {
-       long f_type;
-       long f_bsize;
-       long f_blocks;
-       long f_bfree;
-       long f_bavail;
-       long f_files;
-       long f_ffree;
-       __kernel_fsid_t f_fsid;
-       long f_namelen;
-       long f_frsize;
-       long f_spare[5];
-};
-
-
-struct statfs64 {
-       long f_type;
-       long f_bsize;
-       long f_blocks;
-       long f_bfree;
-       long f_bavail;
-       long f_files;
-       long f_ffree;
-       __kernel_fsid_t f_fsid;
-       long f_namelen;
-       long f_frsize;
-       long f_spare[5];
-};
+#define ARCH_PACK_COMPAT_STATFS64 __attribute__((packed,aligned(4)))
 
-struct compat_statfs64 {
-       __u32 f_type;
-       __u32 f_bsize;
-       __u64 f_blocks;
-       __u64 f_bfree;
-       __u64 f_bavail;
-       __u64 f_files;
-       __u64 f_ffree;
-       __kernel_fsid_t f_fsid;
-       __u32 f_namelen;
-       __u32 f_frsize;
-       __u32 f_spare[5];
-} __attribute__((packed));
+#include <asm-generic/statfs.h>
 
 #endif /* _ASM_IA64_STATFS_H */
index 200100ea7610883ae8fc90768a64ba185aa68d3c..f482a9098e32aadec0fc194befc4906a6be7f6b2 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/bitops.h>
 #include <linux/kexec.h>
 
-#include <asm/a.out.h>
 #include <asm/dma.h>
 #include <asm/ia32.h>
 #include <asm/io.h>
index f57113f1f892b091e7439ee18448459b6df25678..00289c178f895a6ad62a7fb34603af08d52bc961 100644 (file)
@@ -36,9 +36,6 @@ config NO_IOPORT
 config NO_DMA
        def_bool y
 
-config ARCH_SUPPORTS_AOUT
-       def_bool y
-
 config HZ
        int
        default 100
index 8c5e1de68fcb6737bbfb1995b21736ac379fa7cc..41e5bf02e230716f860290555066df3d532440cb 100644 (file)
@@ -5,6 +5,7 @@
 config M68K
        bool
        default y
+       select HAVE_AOUT
        select HAVE_IDE
 
 config MMU
@@ -53,9 +54,6 @@ config NO_IOPORT
 config NO_DMA
        def_bool SUN3
 
-config ARCH_SUPPORTS_AOUT
-       def_bool y
-
 config HZ
        int
        default 100
index 2e7515e8db985a9f4b50820edae74a643cf0f325..0a8998315e5ed9fcdada66d87c5ee1127e35b9ac 100644 (file)
@@ -73,9 +73,6 @@ config GENERIC_CLOCKEVENTS
 config NO_IOPORT
        def_bool y
 
-config ARCH_SUPPORTS_AOUT
-       def_bool y
-
 source "init/Kconfig"
 
 menu "Processor type and features"
diff --git a/arch/m68knommu/include/asm/a.out.h b/arch/m68knommu/include/asm/a.out.h
deleted file mode 100644 (file)
index ce18ef9..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-m68k/a.out.h>
index 47502d5ec19fa18873ca85fcebeae7ff42e9ed16..3f2d7745f31e8321f629b80dd1eceacced2a52e2 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/ptrace.h>
 #include <linux/slab.h>
 #include <linux/user.h>
-#include <linux/a.out.h>
 #include <linux/interrupt.h>
 #include <linux/reboot.h>
 #include <linux/fs.h>
index 46f8f9d0c4089085c2c3888e0c63afa2cbbb0e09..5d5d56bcd0efd5121ff2965f83a6e200b4726866 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/types.h>
-#include <linux/a.out.h>
 #include <linux/user.h>
 #include <linux/string.h>
 #include <linux/linkage.h>
diff --git a/arch/mips/include/asm/a.out.h b/arch/mips/include/asm/a.out.h
deleted file mode 100644 (file)
index cad8371..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1994 - 1999, 2003 by Ralf Baechle
- */
-#ifndef _ASM_A_OUT_H
-#define _ASM_A_OUT_H
-
-#ifdef __KERNEL__
-
-
-#endif
-
-struct exec
-{
-       unsigned long a_info;   /* Use macros N_MAGIC, etc for access */
-       unsigned a_text;        /* length of text, in bytes */
-       unsigned a_data;        /* length of data, in bytes */
-       unsigned a_bss;         /* length of uninitialized data area for
-                                   file, in bytes */
-       unsigned a_syms;        /* length of symbol table data in file,
-                                  in bytes */
-       unsigned a_entry;       /* start address */
-       unsigned a_trsize;      /* length of relocation info for text, in
-                                   bytes */
-       unsigned a_drsize;      /* length of relocation info for data, in bytes */
-};
-
-#define N_TRSIZE(a)    ((a).a_trsize)
-#define N_DRSIZE(a)    ((a).a_drsize)
-#define N_SYMSIZE(a)   ((a).a_syms)
-
-#endif /* _ASM_A_OUT_H */
index 22fc19bbe87f3744ee24ef7dbc81a315b293fc1d..ca2e4026ad20b3c00365d0dc3b85904bbd2e273a 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/personality.h>
 #include <linux/sys.h>
 #include <linux/user.h>
-#include <linux/a.out.h>
 #include <linux/init.h>
 #include <linux/completion.h>
 #include <linux/kallsyms.h>
index 343015a2f418fd9fb741ef6ae7b8821008e1af19..37970d9b2186eed4f26d8b736d731f35fb5d7b72 100644 (file)
@@ -7,7 +7,6 @@
  * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
  * Copyright (C) 2001 MIPS Technologies, Inc.
  */
-#include <linux/a.out.h>
 #include <linux/capability.h>
 #include <linux/errno.h>
 #include <linux/linkage.h>
index e856218da90d36098e719602be9ffaa78c28f606..dd557c9cf001be6226441b78cb84753f5e50cb15 100644 (file)
@@ -53,9 +53,6 @@ config QUICKLIST
 config ARCH_HAS_ILOG2_U32
        def_bool y
 
-config ARCH_SUPPORTS_AOUT
-       def_bool n
-
 # Use the generic interrupt handling code in kernel/irq/
 config GENERIC_HARDIRQS
        def_bool y
index a7d4fd353c2b06fcaa8c7d6e1306e71b14ad440f..8313fccced5e1553f6f3d7ff484d897d2d20b812 100644 (file)
@@ -76,9 +76,6 @@ config IRQ_PER_CPU
        bool
        default y
 
-config ARCH_SUPPORTS_AOUT
-       def_bool y
-
 # unless you want to implement ACPI on PA-RISC ... ;-)
 config PM
        bool
diff --git a/arch/powerpc/include/asm/a.out.h b/arch/powerpc/include/asm/a.out.h
deleted file mode 100644 (file)
index 89cead6..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef _ASM_POWERPC_A_OUT_H
-#define _ASM_POWERPC_A_OUT_H
-
-struct exec
-{
-       unsigned long a_info;   /* Use macros N_MAGIC, etc for access */
-       unsigned a_text;        /* length of text, in bytes */
-       unsigned a_data;        /* length of data, in bytes */
-       unsigned a_bss;         /* length of uninitialized data area for file, in bytes */
-       unsigned a_syms;        /* length of symbol table data in file, in bytes */
-       unsigned a_entry;       /* start address */
-       unsigned a_trsize;      /* length of relocation info for text, in bytes */
-       unsigned a_drsize;      /* length of relocation info for data, in bytes */
-};
-
-#define N_TRSIZE(a)    ((a).a_trsize)
-#define N_DRSIZE(a)    ((a).a_drsize)
-#define N_SYMSIZE(a)   ((a).a_syms)
-
-#endif /* _ASM_POWERPC_A_OUT_H */
index 67024026c10d281dcfe5e3ab602305d6f07cf664..5244834583a42c950c09285f589ed80b0141c9a3 100644 (file)
@@ -1,60 +1,6 @@
 #ifndef _ASM_POWERPC_STATFS_H
 #define _ASM_POWERPC_STATFS_H
 
-/* For ppc32 we just use the generic definitions, not so simple on ppc64 */
-
-#ifndef __powerpc64__
 #include <asm-generic/statfs.h>
-#else
-
-#ifndef __KERNEL_STRICT_NAMES
-#include <linux/types.h>
-typedef __kernel_fsid_t        fsid_t;
-#endif
-
-/*
- * We're already 64-bit, so duplicate the definition
- */
-struct statfs {
-       long f_type;
-       long f_bsize;
-       long f_blocks;
-       long f_bfree;
-       long f_bavail;
-       long f_files;
-       long f_ffree;
-       __kernel_fsid_t f_fsid;
-       long f_namelen;
-       long f_frsize;
-       long f_spare[5];
-};
-
-struct statfs64 {
-       long f_type;
-       long f_bsize;
-       long f_blocks;
-       long f_bfree;
-       long f_bavail;
-       long f_files;
-       long f_ffree;
-       __kernel_fsid_t f_fsid;
-       long f_namelen;
-       long f_frsize;
-       long f_spare[5];
-};
 
-struct compat_statfs64 {
-       __u32 f_type;
-       __u32 f_bsize;
-       __u64 f_blocks;
-       __u64 f_bfree;
-       __u64 f_bavail;
-       __u64 f_files;
-       __u64 f_ffree;
-       __kernel_fsid_t f_fsid;
-       __u32 f_namelen;
-       __u32 f_frsize;
-       __u32 f_spare[5];
-};
-#endif /* ! __powerpc64__ */
 #endif
index c906c4bf68357f7fb65dcf19298269a6d03cfafd..23c8c5e7dc4d0be08d0e153fb597ebc3b7535bc2 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/ptrace.h>
 #include <linux/slab.h>
 #include <linux/user.h>
-#include <linux/a.out.h>
 #include <linux/interrupt.h>
 
 #include <asm/pgtable.h>
index 81ccb8dd1a54d8f95b0ed84f357d6e64e5395ab1..f5def6cf5cd61b0114458c74a5171fe724683267 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/ptrace.h>
 #include <linux/slab.h>
 #include <linux/user.h>
-#include <linux/a.out.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
 #include <linux/module.h>
index 1ba7ce5aafaed24ef6cae57e36dcd21d454c1d94..272d79a8d2896ade7f8f36e22f2b6279077f6793 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/ptrace.h>
 #include <linux/slab.h>
 #include <linux/user.h>
-#include <linux/a.out.h>
 #include <linux/tty.h>
 #include <linux/major.h>
 #include <linux/interrupt.h>
index 364714757cf1a633093a30ef935ca4f4ae5fd762..d4c61c3c9669fabaf76f7f48670f30a7427a7abd 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/ptrace.h>
 #include <linux/slab.h>
 #include <linux/user.h>
-#include <linux/a.out.h>
 #include <linux/tty.h>
 #include <linux/string.h>
 #include <linux/delay.h>
index 88ccf3a08a9c387ef13ac373d3f08e2368460350..82c14d203d8bcc92dfc7e4ba46a96ea16177cb8e 100644 (file)
@@ -33,7 +33,6 @@
 #include <linux/ptrace.h>
 #include <linux/slab.h>
 #include <linux/user.h>
-#include <linux/a.out.h>
 #include <linux/tty.h>
 #include <linux/string.h>
 #include <linux/delay.h>
index 7b01d67b4e48ca40dd4d053ae02a59edc702b326..ec341707e41b2fc7891173afc60298f8017107b4 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/unistd.h>
 #include <linux/slab.h>
 #include <linux/user.h>
-#include <linux/a.out.h>
 #include <linux/tty.h>
 #include <linux/major.h>
 #include <linux/interrupt.h>
index 099a45579190e4764343dfebe85cc05f178293f9..06cc70307eceb96e152e4565b366e3feac3e7353 100644 (file)
 #ifndef __s390x__
 #include <asm-generic/statfs.h>
 #else
+/*
+ * We can't use <asm-generic/statfs.h> because in 64-bit mode
+ * we mix ints of different sizes in our struct statfs.
+ */
 
 #ifndef __KERNEL_STRICT_NAMES
-
 #include <linux/types.h>
-
 typedef __kernel_fsid_t        fsid_t;
-
 #endif
 
-/*
- * This is ugly -- we're already 64-bit clean, so just duplicate the 
- * definitions.
- */
 struct statfs {
        int  f_type;
        int  f_bsize;
index 2ba7183bc1f05572fba2636ce160a5c43400963e..2d2769d766ec7cacc827737bdbea9d73e139cfce 100644 (file)
@@ -15,8 +15,6 @@ header-y += signal_32.h
 header-y += signal_64.h
 header-y += stat_32.h
 header-y += stat_64.h
-header-y += statfs_32.h
-header-y += statfs_64.h
 header-y += unistd_32.h
 header-y += unistd_64.h
 
diff --git a/arch/sparc/include/asm/serial.h b/arch/sparc/include/asm/serial.h
new file mode 100644 (file)
index 0000000..f90d61c
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef __SPARC_SERIAL_H
+#define __SPARC_SERIAL_H
+
+#define BASE_BAUD ( 1843200 / 16 )
+
+#endif /* __SPARC_SERIAL_H */
index 5e937a73743dd85d7b830db6be254be72ed01105..55e607ad461d1ddfded240eb124030a8d4810c98 100644 (file)
@@ -1,8 +1,6 @@
 #ifndef ___ASM_SPARC_STATFS_H
 #define ___ASM_SPARC_STATFS_H
-#if defined(__sparc__) && defined(__arch64__)
-#include <asm/statfs_64.h>
-#else
-#include <asm/statfs_32.h>
-#endif
+
+#include <asm-generic/statfs.h>
+
 #endif
diff --git a/arch/sparc/include/asm/statfs_32.h b/arch/sparc/include/asm/statfs_32.h
deleted file mode 100644 (file)
index 304520f..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _SPARC_STATFS_H
-#define _SPARC_STATFS_H
-
-#include <asm-generic/statfs.h>
-
-#endif
diff --git a/arch/sparc/include/asm/statfs_64.h b/arch/sparc/include/asm/statfs_64.h
deleted file mode 100644 (file)
index 79b3c89..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-#ifndef _SPARC64_STATFS_H
-#define _SPARC64_STATFS_H
-
-#ifndef __KERNEL_STRICT_NAMES
-
-#include <linux/types.h>
-
-typedef __kernel_fsid_t        fsid_t;
-
-#endif
-
-struct statfs {
-       long f_type;
-       long f_bsize;
-       long f_blocks;
-       long f_bfree;
-       long f_bavail;
-       long f_files;
-       long f_ffree;
-       __kernel_fsid_t f_fsid;
-       long f_namelen;
-       long f_frsize;
-       long f_spare[5];
-};
-
-struct statfs64 {
-       long f_type;
-       long f_bsize;
-       long f_blocks;
-       long f_bfree;
-       long f_bavail;
-       long f_files;
-       long f_ffree;
-       __kernel_fsid_t f_fsid;
-       long f_namelen;
-       long f_frsize;
-       long f_spare[5];
-};
-
-struct compat_statfs64 {
-       __u32 f_type;
-       __u32 f_bsize;
-       __u64 f_blocks;
-       __u64 f_bfree;
-       __u64 f_bavail;
-       __u64 f_files;
-       __u64 f_ffree;
-       __kernel_fsid_t f_fsid;
-       __u32 f_namelen;
-       __u32 f_frsize;
-       __u32 f_spare[5];
-};
-
-#endif
index e09edfa560da5c1ec5eb0d40f247d13a5eee29c7..1f57c113df6dab5d6816b829d994958c1ad657e4 100644 (file)
@@ -9,8 +9,9 @@ config UML_X86
        default y
 
 config X86_32
-       bool
-       default y
+       bool
+       default y
+       select HAVE_AOUT
 
 config RWSEM_XCHGADD_ALGORITHM
        def_bool y
@@ -42,6 +43,3 @@ config ARCH_REUSE_HOST_VSYSCALL_AREA
 config GENERIC_HWEIGHT
        bool
        default y
-
-config ARCH_SUPPORTS_AOUT
-       def_bool y
index 5696e7b374b31904b7559d045b7235b4e25bcf3e..40b3407cfe169c9b5d68aef83f06b75a382f85c0 100644 (file)
@@ -37,6 +37,3 @@ config SMP_BROKEN
 config GENERIC_HWEIGHT
        bool
        default y
-
-config ARCH_SUPPORTS_AOUT
-       def_bool y
index d741f35d7b3a3654e20e2ccf780fc54e8c76f1be..14a102e877d66e51a1e28a4f5a64ce23b509050a 100644 (file)
@@ -275,6 +275,8 @@ int line_ioctl(struct tty_struct *tty, struct file * file,
        case TIOCGLTC:
        case TIOCSLTC:
 #endif
+       /* Note: these are out of date as we now have TCGETS2 etc but this
+          whole lot should probably go away */
        case TCGETS:
        case TCSETSF:
        case TCSETSW:
index fc8351f374fd466b8f9b287a6f5d4a2ec3b0fd32..f65c2744d5733971caf75b253070b4e9a821d786 100644 (file)
@@ -18,6 +18,7 @@ config X86_64
 ### Arch settings
 config X86
        def_bool y
+       select HAVE_AOUT if X86_32
        select HAVE_UNSTABLE_SCHED_CLOCK
        select HAVE_IDE
        select HAVE_OPROFILE
@@ -152,9 +153,6 @@ config AUDIT_ARCH
        bool
        default X86_64
 
-config ARCH_SUPPORTS_AOUT
-       def_bool y
-
 config ARCH_SUPPORTS_OPTIMIZED_INLINING
        def_bool y
 
@@ -1885,7 +1883,7 @@ config IA32_EMULATION
 
 config IA32_AOUT
        tristate "IA32 a.out support"
-       depends on IA32_EMULATION && ARCH_SUPPORTS_AOUT
+       depends on IA32_EMULATION
        help
          Support old a.out binaries in the 32bit emulation.
 
index c5f1013605203de94c93af52d105512ace47c1c6..0b7c4a3f0651e8e03e7f0c8ea3083bab77775812 100644 (file)
@@ -38,8 +38,7 @@ config M386
          - "Crusoe" for the Transmeta Crusoe series.
          - "Efficeon" for the Transmeta Efficeon series.
          - "Winchip-C6" for original IDT Winchip.
-         - "Winchip-2" for IDT Winchip 2.
-         - "Winchip-2A" for IDT Winchips with 3dNow! capabilities.
+         - "Winchip-2" for IDT Winchips with 3dNow! capabilities.
          - "GeodeGX1" for Geode GX1 (Cyrix MediaGX).
          - "Geode GX/LX" For AMD Geode GX and LX processors.
          - "CyrixIII/VIA C3" for VIA Cyrix III or VIA C3.
@@ -194,19 +193,11 @@ config MWINCHIPC6
          treat this chip as a 586TSC with some extended instructions
          and alignment requirements.
 
-config MWINCHIP2
-       bool "Winchip-2"
-       depends on X86_32
-       help
-         Select this for an IDT Winchip-2.  Linux and GCC
-         treat this chip as a 586TSC with some extended instructions
-         and alignment requirements.
-
 config MWINCHIP3D
-       bool "Winchip-2A/Winchip-3"
+       bool "Winchip-2/Winchip-2A/Winchip-3"
        depends on X86_32
        help
-         Select this for an IDT Winchip-2A or 3.  Linux and GCC
+         Select this for an IDT Winchip-2, 2A or 3.  Linux and GCC
          treat this chip as a 586TSC with some extended instructions
          and alignment requirements.  Also enable out of order memory
          stores for this CPU, which can increase performance of some
@@ -318,7 +309,7 @@ config X86_L1_CACHE_SHIFT
        int
        default "7" if MPENTIUM4 || X86_GENERIC || GENERIC_CPU || MPSC
        default "4" if X86_ELAN || M486 || M386 || MGEODEGX1
-       default "5" if MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 || MCRUSOE || MEFFICEON || MCYRIXIII || MK6 || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || M586 || MVIAC3_2 || MGEODE_LX
+       default "5" if MWINCHIP3D || MWINCHIPC6 || MCRUSOE || MEFFICEON || MCYRIXIII || MK6 || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || M586 || MVIAC3_2 || MGEODE_LX
        default "6" if MK7 || MK8 || MPENTIUMM || MCORE2 || MVIAC7
 
 config X86_XADD
@@ -360,7 +351,7 @@ config X86_POPAD_OK
 
 config X86_ALIGNMENT_16
        def_bool y
-       depends on MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 || MCYRIXIII || X86_ELAN || MK6 || M586MMX || M586TSC || M586 || M486 || MVIAC3_2 || MGEODEGX1
+       depends on MWINCHIP3D || MWINCHIPC6 || MCYRIXIII || X86_ELAN || MK6 || M586MMX || M586TSC || M586 || M486 || MVIAC3_2 || MGEODEGX1
 
 config X86_INTEL_USERCOPY
        def_bool y
@@ -368,7 +359,7 @@ config X86_INTEL_USERCOPY
 
 config X86_USE_PPRO_CHECKSUM
        def_bool y
-       depends on MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MK8 || MVIAC3_2 || MEFFICEON || MGEODE_LX || MCORE2
+       depends on MWINCHIP3D || MWINCHIPC6 || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MK8 || MVIAC3_2 || MEFFICEON || MGEODE_LX || MCORE2
 
 config X86_USE_3DNOW
        def_bool y
@@ -376,7 +367,7 @@ config X86_USE_3DNOW
 
 config X86_OOSTORE
        def_bool y
-       depends on (MWINCHIP3D || MWINCHIP2 || MWINCHIPC6) && MTRR
+       depends on (MWINCHIP3D || MWINCHIPC6) && MTRR
 
 #
 # P6_NOPs are a relatively minor optimization that require a family >=
@@ -396,7 +387,7 @@ config X86_P6_NOP
 
 config X86_TSC
        def_bool y
-       depends on ((MWINCHIP3D || MWINCHIP2 || MCRUSOE || MEFFICEON || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || MK8 || MVIAC3_2 || MVIAC7 || MGEODEGX1 || MGEODE_LX || MCORE2) && !X86_NUMAQ) || X86_64
+       depends on ((MWINCHIP3D || MCRUSOE || MEFFICEON || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || MK8 || MVIAC3_2 || MVIAC7 || MGEODEGX1 || MGEODE_LX || MCORE2) && !X86_NUMAQ) || X86_64
 
 config X86_CMPXCHG64
        def_bool y
@@ -406,7 +397,7 @@ config X86_CMPXCHG64
 # generates cmov.
 config X86_CMOV
        def_bool y
-       depends on (MK7 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MVIAC3_2 || MVIAC7 || X86_64)
+       depends on (MK8 || MK7 || MCORE2 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MVIAC3_2 || MVIAC7 || MCRUSOE || MEFFICEON || X86_64)
 
 config X86_MINIMUM_CPU_FAMILY
        int
@@ -417,7 +408,7 @@ config X86_MINIMUM_CPU_FAMILY
 
 config X86_DEBUGCTLMSR
        def_bool y
-       depends on !(MK6 || MWINCHIPC6 || MWINCHIP2 || MWINCHIP3D || MCYRIXIII || M586MMX || M586TSC || M586 || M486 || M386)
+       depends on !(MK6 || MWINCHIPC6 || MWINCHIP3D || MCYRIXIII || M586MMX || M586TSC || M586 || M486 || M386)
 
 menuconfig PROCESSOR_SELECT
        bool "Supported processor vendors" if EMBEDDED
index b72b4f7531138cbc4c5042ac90942e752a74b8a4..80177ec052f0378d63caef550e7ea8d805ada907 100644 (file)
@@ -28,7 +28,6 @@ cflags-$(CONFIG_MK8)          += $(call cc-option,-march=k8,-march=athlon)
 cflags-$(CONFIG_MCRUSOE)       += -march=i686 $(align)-functions=0 $(align)-jumps=0 $(align)-loops=0
 cflags-$(CONFIG_MEFFICEON)     += -march=i686 $(call tune,pentium3) $(align)-functions=0 $(align)-jumps=0 $(align)-loops=0
 cflags-$(CONFIG_MWINCHIPC6)    += $(call cc-option,-march=winchip-c6,-march=i586)
-cflags-$(CONFIG_MWINCHIP2)     += $(call cc-option,-march=winchip2,-march=i586)
 cflags-$(CONFIG_MWINCHIP3D)    += $(call cc-option,-march=winchip2,-march=i586)
 cflags-$(CONFIG_MCYRIXIII)     += $(call cc-option,-march=c3,-march=i486) $(align)-functions=0 $(align)-jumps=0 $(align)-loops=0
 cflags-$(CONFIG_MVIAC3_2)      += $(call cc-option,-march=c3-2,-march=i686)
index ca226ca31288254bd40eb45ba55047c04b01bb09..52d0359719d7dda3c15ec870be577e653d829896 100644 (file)
@@ -213,7 +213,6 @@ CONFIG_M686=y
 # CONFIG_MCRUSOE is not set
 # CONFIG_MEFFICEON is not set
 # CONFIG_MWINCHIPC6 is not set
-# CONFIG_MWINCHIP2 is not set
 # CONFIG_MWINCHIP3D is not set
 # CONFIG_MGEODEGX1 is not set
 # CONFIG_MGEODE_LX is not set
index 2c4b1c771e28dd3758388a8a634414577db9fd91..f0a03d7a7d63f2f2c32f7daea043a0935021bba3 100644 (file)
@@ -210,7 +210,6 @@ CONFIG_X86_PC=y
 # CONFIG_MCRUSOE is not set
 # CONFIG_MEFFICEON is not set
 # CONFIG_MWINCHIPC6 is not set
-# CONFIG_MWINCHIP2 is not set
 # CONFIG_MWINCHIP3D is not set
 # CONFIG_MGEODEGX1 is not set
 # CONFIG_MGEODE_LX is not set
index ffc1bb4fed7d1ade2ed385597fd05464fea55528..eb4314768bf7ad7f14e8589fe66876a99dc52b8c 100644 (file)
        .endm 
 
        /* clobbers %eax */     
-       .macro  CLEAR_RREGS
+       .macro  CLEAR_RREGS _r9=rax
        xorl    %eax,%eax
        movq    %rax,R11(%rsp)
        movq    %rax,R10(%rsp)
-       movq    %rax,R9(%rsp)
+       movq    %\_r9,R9(%rsp)
        movq    %rax,R8(%rsp)
        .endm
 
         * We don't reload %eax because syscall_trace_enter() returned
         * the value it wants us to use in the table lookup.
         */
-       .macro LOAD_ARGS32 offset
-       movl \offset(%rsp),%r11d
-       movl \offset+8(%rsp),%r10d
+       .macro LOAD_ARGS32 offset, _r9=0
+       .if \_r9
        movl \offset+16(%rsp),%r9d
-       movl \offset+24(%rsp),%r8d
+       .endif
        movl \offset+40(%rsp),%ecx
        movl \offset+48(%rsp),%edx
        movl \offset+56(%rsp),%esi
@@ -145,7 +144,7 @@ ENTRY(ia32_sysenter_target)
        SAVE_ARGS 0,0,1
        /* no need to do an access_ok check here because rbp has been
           32bit zero extended */ 
-1:     movl    (%rbp),%r9d
+1:     movl    (%rbp),%ebp
        .section __ex_table,"a"
        .quad 1b,ia32_badarg
        .previous       
@@ -157,7 +156,7 @@ ENTRY(ia32_sysenter_target)
        cmpl    $(IA32_NR_syscalls-1),%eax
        ja      ia32_badsys
 sysenter_do_call:
-       IA32_ARG_FIXUP 1
+       IA32_ARG_FIXUP
 sysenter_dispatch:
        call    *ia32_sys_call_table(,%rax,8)
        movq    %rax,RAX-ARGOFFSET(%rsp)
@@ -234,20 +233,17 @@ sysexit_audit:
 #endif
 
 sysenter_tracesys:
-       xchgl   %r9d,%ebp
 #ifdef CONFIG_AUDITSYSCALL
        testl   $(_TIF_WORK_SYSCALL_ENTRY & ~_TIF_SYSCALL_AUDIT),TI_flags(%r10)
        jz      sysenter_auditsys
 #endif
        SAVE_REST
        CLEAR_RREGS
-       movq    %r9,R9(%rsp)
        movq    $-ENOSYS,RAX(%rsp)/* ptrace can change this for a bad syscall */
        movq    %rsp,%rdi        /* &pt_regs -> arg1 */
        call    syscall_trace_enter
        LOAD_ARGS32 ARGOFFSET  /* reload args from stack in case ptrace changed it */
        RESTORE_REST
-       xchgl   %ebp,%r9d
        cmpl    $(IA32_NR_syscalls-1),%eax
        ja      int_ret_from_sys_call /* sysenter_tracesys has set RAX(%rsp) */
        jmp     sysenter_do_call
@@ -314,9 +310,9 @@ ENTRY(ia32_cstar_target)
        testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%r10)
        CFI_REMEMBER_STATE
        jnz   cstar_tracesys
-cstar_do_call: 
        cmpl $IA32_NR_syscalls-1,%eax
        ja  ia32_badsys
+cstar_do_call:
        IA32_ARG_FIXUP 1
 cstar_dispatch:
        call *ia32_sys_call_table(,%rax,8)
@@ -357,15 +353,13 @@ cstar_tracesys:
 #endif
        xchgl %r9d,%ebp
        SAVE_REST
-       CLEAR_RREGS
-       movq %r9,R9(%rsp)
+       CLEAR_RREGS r9
        movq $-ENOSYS,RAX(%rsp) /* ptrace can change this for a bad syscall */
        movq %rsp,%rdi        /* &pt_regs -> arg1 */
        call syscall_trace_enter
-       LOAD_ARGS32 ARGOFFSET  /* reload args from stack in case ptrace changed it */
+       LOAD_ARGS32 ARGOFFSET, 1  /* reload args from stack in case ptrace changed it */
        RESTORE_REST
        xchgl %ebp,%r9d
-       movl RSP-ARGOFFSET(%rsp), %r8d
        cmpl $(IA32_NR_syscalls-1),%eax
        ja int_ret_from_sys_call /* cstar_tracesys has set RAX(%rsp) */
        jmp cstar_do_call
index 5098585f87ce8fdc29fd82fde6e53711238f11cd..0d41f0343dc0753e5be4c97fd8b36460bc0ab2a5 100644 (file)
@@ -23,7 +23,7 @@ CFLAGS_hpet.o         := $(nostackp)
 CFLAGS_tsc.o           := $(nostackp)
 
 obj-y                  := process_$(BITS).o signal_$(BITS).o entry_$(BITS).o
-obj-y                  += traps_$(BITS).o irq_$(BITS).o
+obj-y                  += traps.o irq_$(BITS).o dumpstack_$(BITS).o
 obj-y                  += time_$(BITS).o ioport.o ldt.o
 obj-y                  += setup.o i8259.o irqinit_$(BITS).o setup_percpu.o
 obj-$(CONFIG_X86_VISWS)        += visws_quirks.o
index fb04e49776ba308b2cd8f86315bcb7692122ce80..a84ac7b570e6bb4582788da74a4c570e28fd65e9 100644 (file)
@@ -444,7 +444,7 @@ void __init alternative_instructions(void)
                                            _text, _etext);
 
                /* Only switch to UP mode if we don't immediately boot others */
-               if (num_possible_cpus() == 1 || setup_max_cpus <= 1)
+               if (num_present_cpus() == 1 || setup_max_cpus <= 1)
                        alternatives_smp_switch(0);
        }
 #endif
index a91c57cb666a3c752295875ac4ff14298502f5b7..21c831d96af3d8f8ef63e6403f56fd0e71f5730c 100644 (file)
@@ -295,6 +295,9 @@ static void __setup_APIC_LVTT(unsigned int clocks, int oneshot, int irqen)
  *
  * Vector mappings are hard coded. On K8 only offset 0 (APIC500) and
  * MCE interrupts are supported. Thus MCE offset must be set to 0.
+ *
+ * If mask=1, the LVT entry does not generate interrupts while mask=0
+ * enables the vector. See also the BKDGs.
  */
 
 #define APIC_EILVT_LVTOFF_MCE 0
@@ -319,6 +322,7 @@ u8 setup_APIC_eilvt_ibs(u8 vector, u8 msg_type, u8 mask)
        setup_APIC_eilvt(APIC_EILVT_LVTOFF_IBS, vector, msg_type, mask);
        return APIC_EILVT_LVTOFF_IBS;
 }
+EXPORT_SYMBOL_GPL(setup_APIC_eilvt_ibs);
 
 /*
  * Program the next event, relative to now
index 53898b65a6ae1a7bac6a9145caf1113c39274d84..94ddb69ae15e55f39d195267f73bfbdfa346377d 100644 (file)
@@ -307,6 +307,9 @@ static void __setup_APIC_LVTT(unsigned int clocks, int oneshot, int irqen)
  *
  * Vector mappings are hard coded. On K8 only offset 0 (APIC500) and
  * MCE interrupts are supported. Thus MCE offset must be set to 0.
+ *
+ * If mask=1, the LVT entry does not generate interrupts while mask=0
+ * enables the vector. See also the BKDGs.
  */
 
 #define APIC_EILVT_LVTOFF_MCE 0
@@ -331,6 +334,7 @@ u8 setup_APIC_eilvt_ibs(u8 vector, u8 msg_type, u8 mask)
        setup_APIC_eilvt(APIC_EILVT_LVTOFF_IBS, vector, msg_type, mask);
        return APIC_EILVT_LVTOFF_IBS;
 }
+EXPORT_SYMBOL_GPL(setup_APIC_eilvt_ibs);
 
 /*
  * Program the next event, relative to now
index fb789dd9e691cafffb4d25fc0e26b5c35b4c0869..25581dcb280ea8d3a9c8840cd70fcc726e10b76f 100644 (file)
@@ -124,18 +124,25 @@ static inline int flag_is_changeable_p(u32 flag)
 {
        u32 f1, f2;
 
-       asm("pushfl\n\t"
-           "pushfl\n\t"
-           "popl %0\n\t"
-           "movl %0,%1\n\t"
-           "xorl %2,%0\n\t"
-           "pushl %0\n\t"
-           "popfl\n\t"
-           "pushfl\n\t"
-           "popl %0\n\t"
-           "popfl\n\t"
-           : "=&r" (f1), "=&r" (f2)
-           : "ir" (flag));
+       /*
+        * Cyrix and IDT cpus allow disabling of CPUID
+        * so the code below may return different results
+        * when it is executed before and after enabling
+        * the CPUID. Add "volatile" to not allow gcc to
+        * optimize the subsequent calls to this function.
+        */
+       asm volatile ("pushfl\n\t"
+                     "pushfl\n\t"
+                     "popl %0\n\t"
+                     "movl %0,%1\n\t"
+                     "xorl %2,%0\n\t"
+                     "pushl %0\n\t"
+                     "popfl\n\t"
+                     "pushfl\n\t"
+                     "popl %0\n\t"
+                     "popfl\n\t"
+                     : "=&r" (f1), "=&r" (f2)
+                     : "ir" (flag));
 
        return ((f1^f2) & flag) != 0;
 }
@@ -719,12 +726,24 @@ static void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
 #endif
 }
 
+#ifdef CONFIG_X86_64
+static void vgetcpu_set_mode(void)
+{
+       if (cpu_has(&boot_cpu_data, X86_FEATURE_RDTSCP))
+               vgetcpu_mode = VGETCPU_RDTSCP;
+       else
+               vgetcpu_mode = VGETCPU_LSL;
+}
+#endif
+
 void __init identify_boot_cpu(void)
 {
        identify_cpu(&boot_cpu_data);
 #ifdef CONFIG_X86_32
        sysenter_setup();
        enable_sep_cpu();
+#else
+       vgetcpu_set_mode();
 #endif
 }
 
@@ -797,7 +816,7 @@ void __cpuinit print_cpu_info(struct cpuinfo_x86 *c)
        else if (c->cpuid_level >= 0)
                vendor = c->x86_vendor_id;
 
-       if (vendor && strncmp(c->x86_model_id, vendor, strlen(vendor)))
+       if (vendor && !strstr(c->x86_model_id, vendor))
                printk(KERN_CONT "%s ", vendor);
 
        if (c->x86_model_id[0])
index 395acb12b0d1bfe1a5e1764d00ef4271b00a7e2f..b4f14c6c09d9b12971c1673ebac761515e91a4be 100644 (file)
@@ -66,6 +66,6 @@ struct tss_struct doublefault_tss __cacheline_aligned = {
                .ds             = __USER_DS,
                .fs             = __KERNEL_PERCPU,
 
-               .__cr3          = __phys_addr_const((unsigned long)swapper_pg_dir)
+               .__cr3          = __pa_nodebug(swapper_pg_dir),
        }
 };
diff --git a/arch/x86/kernel/dumpstack_32.c b/arch/x86/kernel/dumpstack_32.c
new file mode 100644 (file)
index 0000000..201ee35
--- /dev/null
@@ -0,0 +1,447 @@
+/*
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *  Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs
+ */
+#include <linux/kallsyms.h>
+#include <linux/kprobes.h>
+#include <linux/uaccess.h>
+#include <linux/utsname.h>
+#include <linux/hardirq.h>
+#include <linux/kdebug.h>
+#include <linux/module.h>
+#include <linux/ptrace.h>
+#include <linux/kexec.h>
+#include <linux/bug.h>
+#include <linux/nmi.h>
+
+#include <asm/stacktrace.h>
+
+#define STACKSLOTS_PER_LINE 8
+#define get_bp(bp) asm("movl %%ebp, %0" : "=r" (bp) :)
+
+int panic_on_unrecovered_nmi;
+int kstack_depth_to_print = 3 * STACKSLOTS_PER_LINE;
+static unsigned int code_bytes = 64;
+static int die_counter;
+
+void printk_address(unsigned long address, int reliable)
+{
+       printk(" [<%p>] %s%pS\n", (void *) address,
+                       reliable ? "" : "? ", (void *) address);
+}
+
+static inline int valid_stack_ptr(struct thread_info *tinfo,
+                       void *p, unsigned int size, void *end)
+{
+       void *t = tinfo;
+       if (end) {
+               if (p < end && p >= (end-THREAD_SIZE))
+                       return 1;
+               else
+                       return 0;
+       }
+       return p > t && p < t + THREAD_SIZE - size;
+}
+
+/* The form of the top of the frame on the stack */
+struct stack_frame {
+       struct stack_frame *next_frame;
+       unsigned long return_address;
+};
+
+static inline unsigned long
+print_context_stack(struct thread_info *tinfo,
+               unsigned long *stack, unsigned long bp,
+               const struct stacktrace_ops *ops, void *data,
+               unsigned long *end)
+{
+       struct stack_frame *frame = (struct stack_frame *)bp;
+
+       while (valid_stack_ptr(tinfo, stack, sizeof(*stack), end)) {
+               unsigned long addr;
+
+               addr = *stack;
+               if (__kernel_text_address(addr)) {
+                       if ((unsigned long) stack == bp + sizeof(long)) {
+                               ops->address(data, addr, 1);
+                               frame = frame->next_frame;
+                               bp = (unsigned long) frame;
+                       } else {
+                               ops->address(data, addr, bp == 0);
+                       }
+               }
+               stack++;
+       }
+       return bp;
+}
+
+void dump_trace(struct task_struct *task, struct pt_regs *regs,
+               unsigned long *stack, unsigned long bp,
+               const struct stacktrace_ops *ops, void *data)
+{
+       if (!task)
+               task = current;
+
+       if (!stack) {
+               unsigned long dummy;
+               stack = &dummy;
+               if (task && task != current)
+                       stack = (unsigned long *)task->thread.sp;
+       }
+
+#ifdef CONFIG_FRAME_POINTER
+       if (!bp) {
+               if (task == current) {
+                       /* Grab bp right from our regs */
+                       get_bp(bp);
+               } else {
+                       /* bp is the last reg pushed by switch_to */
+                       bp = *(unsigned long *) task->thread.sp;
+               }
+       }
+#endif
+
+       for (;;) {
+               struct thread_info *context;
+
+               context = (struct thread_info *)
+                       ((unsigned long)stack & (~(THREAD_SIZE - 1)));
+               bp = print_context_stack(context, stack, bp, ops, data, NULL);
+
+               stack = (unsigned long *)context->previous_esp;
+               if (!stack)
+                       break;
+               if (ops->stack(data, "IRQ") < 0)
+                       break;
+               touch_nmi_watchdog();
+       }
+}
+EXPORT_SYMBOL(dump_trace);
+
+static void
+print_trace_warning_symbol(void *data, char *msg, unsigned long symbol)
+{
+       printk(data);
+       print_symbol(msg, symbol);
+       printk("\n");
+}
+
+static void print_trace_warning(void *data, char *msg)
+{
+       printk("%s%s\n", (char *)data, msg);
+}
+
+static int print_trace_stack(void *data, char *name)
+{
+       printk("%s <%s> ", (char *)data, name);
+       return 0;
+}
+
+/*
+ * Print one address/symbol entries per line.
+ */
+static void print_trace_address(void *data, unsigned long addr, int reliable)
+{
+       touch_nmi_watchdog();
+       printk(data);
+       printk_address(addr, reliable);
+}
+
+static const struct stacktrace_ops print_trace_ops = {
+       .warning = print_trace_warning,
+       .warning_symbol = print_trace_warning_symbol,
+       .stack = print_trace_stack,
+       .address = print_trace_address,
+};
+
+static void
+show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs,
+               unsigned long *stack, unsigned long bp, char *log_lvl)
+{
+       printk("%sCall Trace:\n", log_lvl);
+       dump_trace(task, regs, stack, bp, &print_trace_ops, log_lvl);
+}
+
+void show_trace(struct task_struct *task, struct pt_regs *regs,
+               unsigned long *stack, unsigned long bp)
+{
+       show_trace_log_lvl(task, regs, stack, bp, "");
+}
+
+static void
+show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
+               unsigned long *sp, unsigned long bp, char *log_lvl)
+{
+       unsigned long *stack;
+       int i;
+
+       if (sp == NULL) {
+               if (task)
+                       sp = (unsigned long *)task->thread.sp;
+               else
+                       sp = (unsigned long *)&sp;
+       }
+
+       stack = sp;
+       for (i = 0; i < kstack_depth_to_print; i++) {
+               if (kstack_end(stack))
+                       break;
+               if (i && ((i % STACKSLOTS_PER_LINE) == 0))
+                       printk("\n%s", log_lvl);
+               printk(" %08lx", *stack++);
+               touch_nmi_watchdog();
+       }
+       printk("\n");
+       show_trace_log_lvl(task, regs, sp, bp, log_lvl);
+}
+
+void show_stack(struct task_struct *task, unsigned long *sp)
+{
+       show_stack_log_lvl(task, NULL, sp, 0, "");
+}
+
+/*
+ * The architecture-independent dump_stack generator
+ */
+void dump_stack(void)
+{
+       unsigned long bp = 0;
+       unsigned long stack;
+
+#ifdef CONFIG_FRAME_POINTER
+       if (!bp)
+               get_bp(bp);
+#endif
+
+       printk("Pid: %d, comm: %.20s %s %s %.*s\n",
+               current->pid, current->comm, print_tainted(),
+               init_utsname()->release,
+               (int)strcspn(init_utsname()->version, " "),
+               init_utsname()->version);
+       show_trace(NULL, NULL, &stack, bp);
+}
+
+EXPORT_SYMBOL(dump_stack);
+
+void show_registers(struct pt_regs *regs)
+{
+       int i;
+
+       print_modules();
+       __show_regs(regs, 0);
+
+       printk(KERN_EMERG "Process %.*s (pid: %d, ti=%p task=%p task.ti=%p)\n",
+               TASK_COMM_LEN, current->comm, task_pid_nr(current),
+               current_thread_info(), current, task_thread_info(current));
+       /*
+        * When in-kernel, we also print out the stack and code at the
+        * time of the fault..
+        */
+       if (!user_mode_vm(regs)) {
+               unsigned int code_prologue = code_bytes * 43 / 64;
+               unsigned int code_len = code_bytes;
+               unsigned char c;
+               u8 *ip;
+
+               printk(KERN_EMERG "Stack:\n");
+               show_stack_log_lvl(NULL, regs, &regs->sp,
+                               0, KERN_EMERG);
+
+               printk(KERN_EMERG "Code: ");
+
+               ip = (u8 *)regs->ip - code_prologue;
+               if (ip < (u8 *)PAGE_OFFSET || probe_kernel_address(ip, c)) {
+                       /* try starting at IP */
+                       ip = (u8 *)regs->ip;
+                       code_len = code_len - code_prologue + 1;
+               }
+               for (i = 0; i < code_len; i++, ip++) {
+                       if (ip < (u8 *)PAGE_OFFSET ||
+                                       probe_kernel_address(ip, c)) {
+                               printk(" Bad EIP value.");
+                               break;
+                       }
+                       if (ip == (u8 *)regs->ip)
+                               printk("<%02x> ", c);
+                       else
+                               printk("%02x ", c);
+               }
+       }
+       printk("\n");
+}
+
+int is_valid_bugaddr(unsigned long ip)
+{
+       unsigned short ud2;
+
+       if (ip < PAGE_OFFSET)
+               return 0;
+       if (probe_kernel_address((unsigned short *)ip, ud2))
+               return 0;
+
+       return ud2 == 0x0b0f;
+}
+
+static raw_spinlock_t die_lock = __RAW_SPIN_LOCK_UNLOCKED;
+static int die_owner = -1;
+static unsigned int die_nest_count;
+
+unsigned __kprobes long oops_begin(void)
+{
+       unsigned long flags;
+
+       oops_enter();
+
+       if (die_owner != raw_smp_processor_id()) {
+               console_verbose();
+               raw_local_irq_save(flags);
+               __raw_spin_lock(&die_lock);
+               die_owner = smp_processor_id();
+               die_nest_count = 0;
+               bust_spinlocks(1);
+       } else {
+               raw_local_irq_save(flags);
+       }
+       die_nest_count++;
+       return flags;
+}
+
+void __kprobes oops_end(unsigned long flags, struct pt_regs *regs, int signr)
+{
+       bust_spinlocks(0);
+       die_owner = -1;
+       add_taint(TAINT_DIE);
+       __raw_spin_unlock(&die_lock);
+       raw_local_irq_restore(flags);
+
+       if (!regs)
+               return;
+
+       if (kexec_should_crash(current))
+               crash_kexec(regs);
+       if (in_interrupt())
+               panic("Fatal exception in interrupt");
+       if (panic_on_oops)
+               panic("Fatal exception");
+       oops_exit();
+       do_exit(signr);
+}
+
+int __kprobes __die(const char *str, struct pt_regs *regs, long err)
+{
+       unsigned short ss;
+       unsigned long sp;
+
+       printk(KERN_EMERG "%s: %04lx [#%d] ", str, err & 0xffff, ++die_counter);
+#ifdef CONFIG_PREEMPT
+       printk("PREEMPT ");
+#endif
+#ifdef CONFIG_SMP
+       printk("SMP ");
+#endif
+#ifdef CONFIG_DEBUG_PAGEALLOC
+       printk("DEBUG_PAGEALLOC");
+#endif
+       printk("\n");
+       if (notify_die(DIE_OOPS, str, regs, err,
+                       current->thread.trap_no, SIGSEGV) == NOTIFY_STOP)
+               return 1;
+
+       show_registers(regs);
+       /* Executive summary in case the oops scrolled away */
+       sp = (unsigned long) (&regs->sp);
+       savesegment(ss, ss);
+       if (user_mode(regs)) {
+               sp = regs->sp;
+               ss = regs->ss & 0xffff;
+       }
+       printk(KERN_EMERG "EIP: [<%08lx>] ", regs->ip);
+       print_symbol("%s", regs->ip);
+       printk(" SS:ESP %04x:%08lx\n", ss, sp);
+       return 0;
+}
+
+/*
+ * This is gone through when something in the kernel has done something bad
+ * and is about to be terminated:
+ */
+void die(const char *str, struct pt_regs *regs, long err)
+{
+       unsigned long flags = oops_begin();
+
+       if (die_nest_count < 3) {
+               report_bug(regs->ip, regs);
+
+               if (__die(str, regs, err))
+                       regs = NULL;
+       } else {
+               printk(KERN_EMERG "Recursive die() failure, output suppressed\n");
+       }
+
+       oops_end(flags, regs, SIGSEGV);
+}
+
+static DEFINE_SPINLOCK(nmi_print_lock);
+
+void notrace __kprobes
+die_nmi(char *str, struct pt_regs *regs, int do_panic)
+{
+       if (notify_die(DIE_NMIWATCHDOG, str, regs, 0, 2, SIGINT) == NOTIFY_STOP)
+               return;
+
+       spin_lock(&nmi_print_lock);
+       /*
+       * We are in trouble anyway, lets at least try
+       * to get a message out:
+       */
+       bust_spinlocks(1);
+       printk(KERN_EMERG "%s", str);
+       printk(" on CPU%d, ip %08lx, registers:\n",
+               smp_processor_id(), regs->ip);
+       show_registers(regs);
+       if (do_panic)
+               panic("Non maskable interrupt");
+       console_silent();
+       spin_unlock(&nmi_print_lock);
+       bust_spinlocks(0);
+
+       /*
+        * If we are in kernel we are probably nested up pretty bad
+        * and might aswell get out now while we still can:
+        */
+       if (!user_mode_vm(regs)) {
+               current->thread.trap_no = 2;
+               crash_kexec(regs);
+       }
+
+       do_exit(SIGSEGV);
+}
+
+static int __init oops_setup(char *s)
+{
+       if (!s)
+               return -EINVAL;
+       if (!strcmp(s, "panic"))
+               panic_on_oops = 1;
+       return 0;
+}
+early_param("oops", oops_setup);
+
+static int __init kstack_setup(char *s)
+{
+       if (!s)
+               return -EINVAL;
+       kstack_depth_to_print = simple_strtoul(s, NULL, 0);
+       return 0;
+}
+early_param("kstack", kstack_setup);
+
+static int __init code_bytes_setup(char *s)
+{
+       code_bytes = simple_strtoul(s, NULL, 0);
+       if (code_bytes > 8192)
+               code_bytes = 8192;
+
+       return 1;
+}
+__setup("code_bytes=", code_bytes_setup);
diff --git a/arch/x86/kernel/dumpstack_64.c b/arch/x86/kernel/dumpstack_64.c
new file mode 100644 (file)
index 0000000..086cc81
--- /dev/null
@@ -0,0 +1,573 @@
+/*
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *  Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs
+ */
+#include <linux/kallsyms.h>
+#include <linux/kprobes.h>
+#include <linux/uaccess.h>
+#include <linux/utsname.h>
+#include <linux/hardirq.h>
+#include <linux/kdebug.h>
+#include <linux/module.h>
+#include <linux/ptrace.h>
+#include <linux/kexec.h>
+#include <linux/bug.h>
+#include <linux/nmi.h>
+
+#include <asm/stacktrace.h>
+
+#define STACKSLOTS_PER_LINE 4
+#define get_bp(bp) asm("movq %%rbp, %0" : "=r" (bp) :)
+
+int panic_on_unrecovered_nmi;
+int kstack_depth_to_print = 3 * STACKSLOTS_PER_LINE;
+static unsigned int code_bytes = 64;
+static int die_counter;
+
+void printk_address(unsigned long address, int reliable)
+{
+       printk(" [<%p>] %s%pS\n", (void *) address,
+                       reliable ? "" : "? ", (void *) address);
+}
+
+static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack,
+                                       unsigned *usedp, char **idp)
+{
+       static char ids[][8] = {
+               [DEBUG_STACK - 1] = "#DB",
+               [NMI_STACK - 1] = "NMI",
+               [DOUBLEFAULT_STACK - 1] = "#DF",
+               [STACKFAULT_STACK - 1] = "#SS",
+               [MCE_STACK - 1] = "#MC",
+#if DEBUG_STKSZ > EXCEPTION_STKSZ
+               [N_EXCEPTION_STACKS ...
+                       N_EXCEPTION_STACKS + DEBUG_STKSZ / EXCEPTION_STKSZ - 2] = "#DB[?]"
+#endif
+       };
+       unsigned k;
+
+       /*
+        * Iterate over all exception stacks, and figure out whether
+        * 'stack' is in one of them:
+        */
+       for (k = 0; k < N_EXCEPTION_STACKS; k++) {
+               unsigned long end = per_cpu(orig_ist, cpu).ist[k];
+               /*
+                * Is 'stack' above this exception frame's end?
+                * If yes then skip to the next frame.
+                */
+               if (stack >= end)
+                       continue;
+               /*
+                * Is 'stack' above this exception frame's start address?
+                * If yes then we found the right frame.
+                */
+               if (stack >= end - EXCEPTION_STKSZ) {
+                       /*
+                        * Make sure we only iterate through an exception
+                        * stack once. If it comes up for the second time
+                        * then there's something wrong going on - just
+                        * break out and return NULL:
+                        */
+                       if (*usedp & (1U << k))
+                               break;
+                       *usedp |= 1U << k;
+                       *idp = ids[k];
+                       return (unsigned long *)end;
+               }
+               /*
+                * If this is a debug stack, and if it has a larger size than
+                * the usual exception stacks, then 'stack' might still
+                * be within the lower portion of the debug stack:
+                */
+#if DEBUG_STKSZ > EXCEPTION_STKSZ
+               if (k == DEBUG_STACK - 1 && stack >= end - DEBUG_STKSZ) {
+                       unsigned j = N_EXCEPTION_STACKS - 1;
+
+                       /*
+                        * Black magic. A large debug stack is composed of
+                        * multiple exception stack entries, which we
+                        * iterate through now. Dont look:
+                        */
+                       do {
+                               ++j;
+                               end -= EXCEPTION_STKSZ;
+                               ids[j][4] = '1' + (j - N_EXCEPTION_STACKS);
+                       } while (stack < end - EXCEPTION_STKSZ);
+                       if (*usedp & (1U << j))
+                               break;
+                       *usedp |= 1U << j;
+                       *idp = ids[j];
+                       return (unsigned long *)end;
+               }
+#endif
+       }
+       return NULL;
+}
+
+/*
+ * x86-64 can have up to three kernel stacks:
+ * process stack
+ * interrupt stack
+ * severe exception (double fault, nmi, stack fault, debug, mce) hardware stack
+ */
+
+static inline int valid_stack_ptr(struct thread_info *tinfo,
+                       void *p, unsigned int size, void *end)
+{
+       void *t = tinfo;
+       if (end) {
+               if (p < end && p >= (end-THREAD_SIZE))
+                       return 1;
+               else
+                       return 0;
+       }
+       return p > t && p < t + THREAD_SIZE - size;
+}
+
+/* The form of the top of the frame on the stack */
+struct stack_frame {
+       struct stack_frame *next_frame;
+       unsigned long return_address;
+};
+
+static inline unsigned long
+print_context_stack(struct thread_info *tinfo,
+               unsigned long *stack, unsigned long bp,
+               const struct stacktrace_ops *ops, void *data,
+               unsigned long *end)
+{
+       struct stack_frame *frame = (struct stack_frame *)bp;
+
+       while (valid_stack_ptr(tinfo, stack, sizeof(*stack), end)) {
+               unsigned long addr;
+
+               addr = *stack;
+               if (__kernel_text_address(addr)) {
+                       if ((unsigned long) stack == bp + sizeof(long)) {
+                               ops->address(data, addr, 1);
+                               frame = frame->next_frame;
+                               bp = (unsigned long) frame;
+                       } else {
+                               ops->address(data, addr, bp == 0);
+                       }
+               }
+               stack++;
+       }
+       return bp;
+}
+
+void dump_trace(struct task_struct *task, struct pt_regs *regs,
+               unsigned long *stack, unsigned long bp,
+               const struct stacktrace_ops *ops, void *data)
+{
+       const unsigned cpu = get_cpu();
+       unsigned long *irqstack_end = (unsigned long *)cpu_pda(cpu)->irqstackptr;
+       unsigned used = 0;
+       struct thread_info *tinfo;
+
+       if (!task)
+               task = current;
+
+       if (!stack) {
+               unsigned long dummy;
+               stack = &dummy;
+               if (task && task != current)
+                       stack = (unsigned long *)task->thread.sp;
+       }
+
+#ifdef CONFIG_FRAME_POINTER
+       if (!bp) {
+               if (task == current) {
+                       /* Grab bp right from our regs */
+                       get_bp(bp);
+               } else {
+                       /* bp is the last reg pushed by switch_to */
+                       bp = *(unsigned long *) task->thread.sp;
+               }
+       }
+#endif
+
+       /*
+        * Print function call entries in all stacks, starting at the
+        * current stack address. If the stacks consist of nested
+        * exceptions
+        */
+       tinfo = task_thread_info(task);
+       for (;;) {
+               char *id;
+               unsigned long *estack_end;
+               estack_end = in_exception_stack(cpu, (unsigned long)stack,
+                                               &used, &id);
+
+               if (estack_end) {
+                       if (ops->stack(data, id) < 0)
+                               break;
+
+                       bp = print_context_stack(tinfo, stack, bp, ops,
+                                                       data, estack_end);
+                       ops->stack(data, "<EOE>");
+                       /*
+                        * We link to the next stack via the
+                        * second-to-last pointer (index -2 to end) in the
+                        * exception stack:
+                        */
+                       stack = (unsigned long *) estack_end[-2];
+                       continue;
+               }
+               if (irqstack_end) {
+                       unsigned long *irqstack;
+                       irqstack = irqstack_end -
+                               (IRQSTACKSIZE - 64) / sizeof(*irqstack);
+
+                       if (stack >= irqstack && stack < irqstack_end) {
+                               if (ops->stack(data, "IRQ") < 0)
+                                       break;
+                               bp = print_context_stack(tinfo, stack, bp,
+                                               ops, data, irqstack_end);
+                               /*
+                                * We link to the next stack (which would be
+                                * the process stack normally) the last
+                                * pointer (index -1 to end) in the IRQ stack:
+                                */
+                               stack = (unsigned long *) (irqstack_end[-1]);
+                               irqstack_end = NULL;
+                               ops->stack(data, "EOI");
+                               continue;
+                       }
+               }
+               break;
+       }
+
+       /*
+        * This handles the process stack:
+        */
+       bp = print_context_stack(tinfo, stack, bp, ops, data, NULL);
+       put_cpu();
+}
+EXPORT_SYMBOL(dump_trace);
+
+static void
+print_trace_warning_symbol(void *data, char *msg, unsigned long symbol)
+{
+       printk(data);
+       print_symbol(msg, symbol);
+       printk("\n");
+}
+
+static void print_trace_warning(void *data, char *msg)
+{
+       printk("%s%s\n", (char *)data, msg);
+}
+
+static int print_trace_stack(void *data, char *name)
+{
+       printk("%s <%s> ", (char *)data, name);
+       return 0;
+}
+
+/*
+ * Print one address/symbol entries per line.
+ */
+static void print_trace_address(void *data, unsigned long addr, int reliable)
+{
+       touch_nmi_watchdog();
+       printk(data);
+       printk_address(addr, reliable);
+}
+
+static const struct stacktrace_ops print_trace_ops = {
+       .warning = print_trace_warning,
+       .warning_symbol = print_trace_warning_symbol,
+       .stack = print_trace_stack,
+       .address = print_trace_address,
+};
+
+static void
+show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs,
+               unsigned long *stack, unsigned long bp, char *log_lvl)
+{
+       printk("%sCall Trace:\n", log_lvl);
+       dump_trace(task, regs, stack, bp, &print_trace_ops, log_lvl);
+}
+
+void show_trace(struct task_struct *task, struct pt_regs *regs,
+               unsigned long *stack, unsigned long bp)
+{
+       show_trace_log_lvl(task, regs, stack, bp, "");
+}
+
+static void
+show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
+               unsigned long *sp, unsigned long bp, char *log_lvl)
+{
+       unsigned long *stack;
+       int i;
+       const int cpu = smp_processor_id();
+       unsigned long *irqstack_end =
+               (unsigned long *) (cpu_pda(cpu)->irqstackptr);
+       unsigned long *irqstack =
+               (unsigned long *) (cpu_pda(cpu)->irqstackptr - IRQSTACKSIZE);
+
+       /*
+        * debugging aid: "show_stack(NULL, NULL);" prints the
+        * back trace for this cpu.
+        */
+
+       if (sp == NULL) {
+               if (task)
+                       sp = (unsigned long *)task->thread.sp;
+               else
+                       sp = (unsigned long *)&sp;
+       }
+
+       stack = sp;
+       for (i = 0; i < kstack_depth_to_print; i++) {
+               if (stack >= irqstack && stack <= irqstack_end) {
+                       if (stack == irqstack_end) {
+                               stack = (unsigned long *) (irqstack_end[-1]);
+                               printk(" <EOI> ");
+                       }
+               } else {
+               if (((long) stack & (THREAD_SIZE-1)) == 0)
+                       break;
+               }
+               if (i && ((i % STACKSLOTS_PER_LINE) == 0))
+                       printk("\n%s", log_lvl);
+               printk(" %016lx", *stack++);
+               touch_nmi_watchdog();
+       }
+       printk("\n");
+       show_trace_log_lvl(task, regs, sp, bp, log_lvl);
+}
+
+void show_stack(struct task_struct *task, unsigned long *sp)
+{
+       show_stack_log_lvl(task, NULL, sp, 0, "");
+}
+
+/*
+ * The architecture-independent dump_stack generator
+ */
+void dump_stack(void)
+{
+       unsigned long bp = 0;
+       unsigned long stack;
+
+#ifdef CONFIG_FRAME_POINTER
+       if (!bp)
+               get_bp(bp);
+#endif
+
+       printk("Pid: %d, comm: %.20s %s %s %.*s\n",
+               current->pid, current->comm, print_tainted(),
+               init_utsname()->release,
+               (int)strcspn(init_utsname()->version, " "),
+               init_utsname()->version);
+       show_trace(NULL, NULL, &stack, bp);
+}
+EXPORT_SYMBOL(dump_stack);
+
+void show_registers(struct pt_regs *regs)
+{
+       int i;
+       unsigned long sp;
+       const int cpu = smp_processor_id();
+       struct task_struct *cur = cpu_pda(cpu)->pcurrent;
+
+       sp = regs->sp;
+       printk("CPU %d ", cpu);
+       __show_regs(regs, 1);
+       printk("Process %s (pid: %d, threadinfo %p, task %p)\n",
+               cur->comm, cur->pid, task_thread_info(cur), cur);
+
+       /*
+        * When in-kernel, we also print out the stack and code at the
+        * time of the fault..
+        */
+       if (!user_mode(regs)) {
+               unsigned int code_prologue = code_bytes * 43 / 64;
+               unsigned int code_len = code_bytes;
+               unsigned char c;
+               u8 *ip;
+
+               printk(KERN_EMERG "Stack:\n");
+               show_stack_log_lvl(NULL, regs, (unsigned long *)sp,
+                               regs->bp, KERN_EMERG);
+
+               printk(KERN_EMERG "Code: ");
+
+               ip = (u8 *)regs->ip - code_prologue;
+               if (ip < (u8 *)PAGE_OFFSET || probe_kernel_address(ip, c)) {
+                       /* try starting at IP */
+                       ip = (u8 *)regs->ip;
+                       code_len = code_len - code_prologue + 1;
+               }
+               for (i = 0; i < code_len; i++, ip++) {
+                       if (ip < (u8 *)PAGE_OFFSET ||
+                                       probe_kernel_address(ip, c)) {
+                               printk(" Bad RIP value.");
+                               break;
+                       }
+                       if (ip == (u8 *)regs->ip)
+                               printk("<%02x> ", c);
+                       else
+                               printk("%02x ", c);
+               }
+       }
+       printk("\n");
+}
+
+int is_valid_bugaddr(unsigned long ip)
+{
+       unsigned short ud2;
+
+       if (__copy_from_user(&ud2, (const void __user *) ip, sizeof(ud2)))
+               return 0;
+
+       return ud2 == 0x0b0f;
+}
+
+static raw_spinlock_t die_lock = __RAW_SPIN_LOCK_UNLOCKED;
+static int die_owner = -1;
+static unsigned int die_nest_count;
+
+unsigned __kprobes long oops_begin(void)
+{
+       int cpu;
+       unsigned long flags;
+
+       oops_enter();
+
+       /* racy, but better than risking deadlock. */
+       raw_local_irq_save(flags);
+       cpu = smp_processor_id();
+       if (!__raw_spin_trylock(&die_lock)) {
+               if (cpu == die_owner)
+                       /* nested oops. should stop eventually */;
+               else
+                       __raw_spin_lock(&die_lock);
+       }
+       die_nest_count++;
+       die_owner = cpu;
+       console_verbose();
+       bust_spinlocks(1);
+       return flags;
+}
+
+void __kprobes oops_end(unsigned long flags, struct pt_regs *regs, int signr)
+{
+       die_owner = -1;
+       bust_spinlocks(0);
+       die_nest_count--;
+       if (!die_nest_count)
+               /* Nest count reaches zero, release the lock. */
+               __raw_spin_unlock(&die_lock);
+       raw_local_irq_restore(flags);
+       if (!regs) {
+               oops_exit();
+               return;
+       }
+       if (in_interrupt())
+               panic("Fatal exception in interrupt");
+       if (panic_on_oops)
+               panic("Fatal exception");
+       oops_exit();
+       do_exit(signr);
+}
+
+int __kprobes __die(const char *str, struct pt_regs *regs, long err)
+{
+       printk(KERN_EMERG "%s: %04lx [#%d] ", str, err & 0xffff, ++die_counter);
+#ifdef CONFIG_PREEMPT
+       printk("PREEMPT ");
+#endif
+#ifdef CONFIG_SMP
+       printk("SMP ");
+#endif
+#ifdef CONFIG_DEBUG_PAGEALLOC
+       printk("DEBUG_PAGEALLOC");
+#endif
+       printk("\n");
+       if (notify_die(DIE_OOPS, str, regs, err,
+                       current->thread.trap_no, SIGSEGV) == NOTIFY_STOP)
+               return 1;
+
+       show_registers(regs);
+       add_taint(TAINT_DIE);
+       /* Executive summary in case the oops scrolled away */
+       printk(KERN_ALERT "RIP ");
+       printk_address(regs->ip, 1);
+       printk(" RSP <%016lx>\n", regs->sp);
+       if (kexec_should_crash(current))
+               crash_kexec(regs);
+       return 0;
+}
+
+void die(const char *str, struct pt_regs *regs, long err)
+{
+       unsigned long flags = oops_begin();
+
+       if (!user_mode(regs))
+               report_bug(regs->ip, regs);
+
+       if (__die(str, regs, err))
+               regs = NULL;
+       oops_end(flags, regs, SIGSEGV);
+}
+
+notrace __kprobes void
+die_nmi(char *str, struct pt_regs *regs, int do_panic)
+{
+       unsigned long flags;
+
+       if (notify_die(DIE_NMIWATCHDOG, str, regs, 0, 2, SIGINT) == NOTIFY_STOP)
+               return;
+
+       flags = oops_begin();
+       /*
+        * We are in trouble anyway, lets at least try
+        * to get a message out.
+        */
+       printk(KERN_EMERG "%s", str);
+       printk(" on CPU%d, ip %08lx, registers:\n",
+               smp_processor_id(), regs->ip);
+       show_registers(regs);
+       if (kexec_should_crash(current))
+               crash_kexec(regs);
+       if (do_panic || panic_on_oops)
+               panic("Non maskable interrupt");
+       oops_end(flags, NULL, SIGBUS);
+       nmi_exit();
+       local_irq_enable();
+       do_exit(SIGBUS);
+}
+
+static int __init oops_setup(char *s)
+{
+       if (!s)
+               return -EINVAL;
+       if (!strcmp(s, "panic"))
+               panic_on_oops = 1;
+       return 0;
+}
+early_param("oops", oops_setup);
+
+static int __init kstack_setup(char *s)
+{
+       if (!s)
+               return -EINVAL;
+       kstack_depth_to_print = simple_strtoul(s, NULL, 0);
+       return 0;
+}
+early_param("kstack", kstack_setup);
+
+static int __init code_bytes_setup(char *s)
+{
+       code_bytes = simple_strtoul(s, NULL, 0);
+       if (code_bytes > 8192)
+               code_bytes = 8192;
+
+       return 1;
+}
+__setup("code_bytes=", code_bytes_setup);
index 109792bc7cfa178e50e07e81ae33dc9e6700a597..b21fbfaffe391a974d10d7417a9f00c99ab05228 100644 (file)
@@ -730,6 +730,7 @@ error_code:
        movl $(__USER_DS), %ecx
        movl %ecx, %ds
        movl %ecx, %es
+       TRACE_IRQS_OFF
        movl %esp,%eax                  # pt_regs pointer
        call *%edi
        jmp ret_from_exception
@@ -760,20 +761,9 @@ ENTRY(device_not_available)
        RING0_INT_FRAME
        pushl $-1                       # mark this as an int
        CFI_ADJUST_CFA_OFFSET 4
-       SAVE_ALL
-       GET_CR0_INTO_EAX
-       testl $0x4, %eax                # EM (math emulation bit)
-       jne device_not_available_emulate
-       preempt_stop(CLBR_ANY)
-       call math_state_restore
-       jmp ret_from_exception
-device_not_available_emulate:
-       pushl $0                        # temporary storage for ORIG_EIP
+       pushl $do_device_not_available
        CFI_ADJUST_CFA_OFFSET 4
-       call math_emulate
-       addl $4, %esp
-       CFI_ADJUST_CFA_OFFSET -4
-       jmp ret_from_exception
+       jmp error_code
        CFI_ENDPROC
 END(device_not_available)
 
@@ -814,6 +804,7 @@ debug_stack_correct:
        pushl $-1                       # mark this as an int
        CFI_ADJUST_CFA_OFFSET 4
        SAVE_ALL
+       TRACE_IRQS_OFF
        xorl %edx,%edx                  # error code 0
        movl %esp,%eax                  # pt_regs pointer
        call do_debug
@@ -858,6 +849,7 @@ nmi_stack_correct:
        pushl %eax
        CFI_ADJUST_CFA_OFFSET 4
        SAVE_ALL
+       TRACE_IRQS_OFF
        xorl %edx,%edx          # zero error code
        movl %esp,%eax          # pt_regs pointer
        call do_nmi
@@ -898,6 +890,7 @@ nmi_espfix_stack:
        pushl %eax
        CFI_ADJUST_CFA_OFFSET 4
        SAVE_ALL
+       TRACE_IRQS_OFF
        FIXUP_ESPFIX_STACK              # %eax == %esp
        xorl %edx,%edx                  # zero error code
        call do_nmi
@@ -928,6 +921,7 @@ KPROBE_ENTRY(int3)
        pushl $-1                       # mark this as an int
        CFI_ADJUST_CFA_OFFSET 4
        SAVE_ALL
+       TRACE_IRQS_OFF
        xorl %edx,%edx          # zero error code
        movl %esp,%eax          # pt_regs pointer
        call do_int3
@@ -1030,7 +1024,7 @@ ENTRY(machine_check)
        RING0_INT_FRAME
        pushl $0
        CFI_ADJUST_CFA_OFFSET 4
-       pushl machine_check_vector
+       pushl $do_machine_check
        CFI_ADJUST_CFA_OFFSET 4
        jmp error_code
        CFI_ENDPROC
index cf3a0b2d00599adb2a79fefa991c0d8223059fba..1db6ce4314e19325a740e15fc1ec60db3de8cf38 100644 (file)
@@ -667,6 +667,13 @@ END(stub_rt_sigreturn)
        SAVE_ARGS
        leaq -ARGOFFSET(%rsp),%rdi      # arg1 for handler
        pushq %rbp
+       /*
+        * Save rbp twice: One is for marking the stack frame, as usual, and the
+        * other, to fill pt_regs properly. This is because bx comes right
+        * before the last saved register in that structure, and not bp. If the
+        * base pointer were in the place bx is today, this would not be needed.
+        */
+       movq %rbp, -8(%rsp)
        CFI_ADJUST_CFA_OFFSET   8
        CFI_REL_OFFSET          rbp, 0
        movq %rsp,%rbp
@@ -932,6 +939,9 @@ END(spurious_interrupt)
        .if \ist
        movq    %gs:pda_data_offset, %rbp
        .endif
+       .if \irqtrace
+       TRACE_IRQS_OFF
+       .endif
        movq %rsp,%rdi
        movq ORIG_RAX(%rsp),%rsi
        movq $-1,ORIG_RAX(%rsp)
@@ -1058,7 +1068,8 @@ KPROBE_ENTRY(error_entry)
        je  error_kernelspace
 error_swapgs:  
        SWAPGS
-error_sti:     
+error_sti:
+       TRACE_IRQS_OFF
        movq %rdi,RDI(%rsp)     
        CFI_REL_OFFSET  rdi,RDI
        movq %rsp,%rdi
@@ -1232,7 +1243,7 @@ ENTRY(simd_coprocessor_error)
 END(simd_coprocessor_error)
 
 ENTRY(device_not_available)
-       zeroentry math_state_restore
+       zeroentry do_device_not_available
 END(device_not_available)
 
        /* runs on exception stack */
index 849e5cd485b8a2184296745751a0ed527b1f831e..f454c78fcef6c7172db2fc0088548974f2f083e1 100644 (file)
@@ -109,6 +109,7 @@ struct oem_table {
 };
 
 extern int find_unisys_acpi_oem_table(unsigned long *oem_addr);
+extern void unmap_unisys_acpi_oem_table(unsigned long oem_addr);
 #endif
 
 struct mip_reg {
@@ -243,21 +244,38 @@ parse_unisys_oem (char *oemptr)
 }
 
 #ifdef CONFIG_ACPI
-int __init
-find_unisys_acpi_oem_table(unsigned long *oem_addr)
+static unsigned long oem_addrX;
+static unsigned long oem_size;
+int __init find_unisys_acpi_oem_table(unsigned long *oem_addr)
 {
        struct acpi_table_header *header = NULL;
        int i = 0;
-       while (ACPI_SUCCESS(acpi_get_table("OEM1", i++, &header))) {
+       acpi_size tbl_size;
+
+       while (ACPI_SUCCESS(acpi_get_table_with_size("OEM1", i++, &header, &tbl_size))) {
                if (!memcmp((char *) &header->oem_id, "UNISYS", 6)) {
                        struct oem_table *t = (struct oem_table *)header;
-                       *oem_addr = (unsigned long)__acpi_map_table(t->OEMTableAddr,
-                                                                   t->OEMTableSize);
+
+                       oem_addrX = t->OEMTableAddr;
+                       oem_size = t->OEMTableSize;
+                       early_acpi_os_unmap_memory(header, tbl_size);
+
+                       *oem_addr = (unsigned long)__acpi_map_table(oem_addrX,
+                                                                   oem_size);
                        return 0;
                }
+               early_acpi_os_unmap_memory(header, tbl_size);
        }
        return -1;
 }
+
+void __init unmap_unisys_acpi_oem_table(unsigned long oem_addr)
+{
+       if (!oem_addr)
+               return;
+
+       __acpi_unmap_table((char *)oem_addr, oem_size);
+}
 #endif
 
 static void
index ae2ffc8a400ccc131aa8d584a2a9a420f8c40463..33581d94a90e5bebea90a9a26d413524947c7340 100644 (file)
@@ -114,7 +114,7 @@ static void uv_send_IPI_one(int cpu, int vector)
        unsigned long val, apicid, lapicid;
        int pnode;
 
-       apicid = per_cpu(x86_cpu_to_apicid, cpu); /* ZZZ - cache node-local ? */
+       apicid = per_cpu(x86_cpu_to_apicid, cpu);
        lapicid = apicid & 0x3f;                /* ZZZ macro needed */
        pnode = uv_apicid_to_pnode(apicid);
        val =
@@ -202,12 +202,10 @@ static unsigned int phys_pkg_id(int index_msb)
        return uv_read_apic_id() >> index_msb;
 }
 
-#ifdef ZZZ             /* Needs x2apic patch */
 static void uv_send_IPI_self(int vector)
 {
        apic_write(APIC_SELF_IPI, vector);
 }
-#endif
 
 struct genapic apic_x2apic_uv_x = {
        .name = "UV large system",
@@ -215,15 +213,15 @@ struct genapic apic_x2apic_uv_x = {
        .int_delivery_mode = dest_Fixed,
        .int_dest_mode = (APIC_DEST_PHYSICAL != 0),
        .target_cpus = uv_target_cpus,
-       .vector_allocation_domain = uv_vector_allocation_domain,/* Fixme ZZZ */
+       .vector_allocation_domain = uv_vector_allocation_domain,
        .apic_id_registered = uv_apic_id_registered,
        .init_apic_ldr = uv_init_apic_ldr,
        .send_IPI_all = uv_send_IPI_all,
        .send_IPI_allbutself = uv_send_IPI_allbutself,
        .send_IPI_mask = uv_send_IPI_mask,
-       /* ZZZ.send_IPI_self = uv_send_IPI_self, */
+       .send_IPI_self = uv_send_IPI_self,
        .cpu_mask_to_apicid = uv_cpu_mask_to_apicid,
-       .phys_pkg_id = phys_pkg_id,     /* Fixme ZZZ */
+       .phys_pkg_id = phys_pkg_id,
        .get_apic_id = get_apic_id,
        .set_apic_id = set_apic_id,
        .apic_id_mask = (0xFFFFFFFFu),
@@ -286,12 +284,13 @@ static __init void map_low_mmrs(void)
 
 enum map_type {map_wb, map_uc};
 
-static __init void map_high(char *id, unsigned long base, int shift, enum map_type map_type)
+static __init void map_high(char *id, unsigned long base, int shift,
+                           int max_pnode, enum map_type map_type)
 {
        unsigned long bytes, paddr;
 
        paddr = base << shift;
-       bytes = (1UL << shift);
+       bytes = (1UL << shift) * (max_pnode + 1);
        printk(KERN_INFO "UV: Map %s_HI 0x%lx - 0x%lx\n", id, paddr,
                                                paddr + bytes);
        if (map_type == map_uc)
@@ -307,7 +306,7 @@ static __init void map_gru_high(int max_pnode)
 
        gru.v = uv_read_local_mmr(UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR);
        if (gru.s.enable)
-               map_high("GRU", gru.s.base, shift, map_wb);
+               map_high("GRU", gru.s.base, shift, max_pnode, map_wb);
 }
 
 static __init void map_config_high(int max_pnode)
@@ -317,7 +316,7 @@ static __init void map_config_high(int max_pnode)
 
        cfg.v = uv_read_local_mmr(UVH_RH_GAM_CFG_OVERLAY_CONFIG_MMR);
        if (cfg.s.enable)
-               map_high("CONFIG", cfg.s.base, shift, map_uc);
+               map_high("CONFIG", cfg.s.base, shift, max_pnode, map_uc);
 }
 
 static __init void map_mmr_high(int max_pnode)
@@ -327,7 +326,7 @@ static __init void map_mmr_high(int max_pnode)
 
        mmr.v = uv_read_local_mmr(UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR);
        if (mmr.s.enable)
-               map_high("MMR", mmr.s.base, shift, map_uc);
+               map_high("MMR", mmr.s.base, shift, max_pnode, map_uc);
 }
 
 static __init void map_mmioh_high(int max_pnode)
@@ -337,7 +336,7 @@ static __init void map_mmioh_high(int max_pnode)
 
        mmioh.v = uv_read_local_mmr(UVH_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR);
        if (mmioh.s.enable)
-               map_high("MMIOH", mmioh.s.base, shift, map_uc);
+               map_high("MMIOH", mmioh.s.base, shift, max_pnode, map_uc);
 }
 
 static __init void uv_rtc_init(void)
index 3e66bd364a9db3cf8f3fb624f96eeb7075364d78..1dcb0f13897e9b6d4773111e1bc8300713efe0e8 100644 (file)
@@ -35,6 +35,7 @@ void __init reserve_ebda_region(void)
 
        /* start of EBDA area */
        ebda_addr = get_bios_ebda();
+       printk(KERN_INFO "BIOS EBDA/lowmem at: %08x/%08x\n", ebda_addr, lowmem);
 
        /* Fixup: bios puts an EBDA in the top 64K segment */
        /* of conventional memory, but does not adjust lowmem. */
index 73deaffadd036a578984bb8ad6e0455f1044558a..acf62fc233da6c0ee8196d18c53a9a55d31bd10f 100644 (file)
@@ -115,13 +115,17 @@ static void hpet_reserve_platform_timers(unsigned long id)
        hd.hd_phys_address = hpet_address;
        hd.hd_address = hpet;
        hd.hd_nirqs = nrtimers;
-       hd.hd_flags = HPET_DATA_PLATFORM;
        hpet_reserve_timer(&hd, 0);
 
 #ifdef CONFIG_HPET_EMULATE_RTC
        hpet_reserve_timer(&hd, 1);
 #endif
 
+       /*
+        * NOTE that hd_irq[] reflects IOAPIC input pins (LEGACY_8254
+        * is wrong for i8259!) not the output IRQ.  Many BIOS writers
+        * don't bother configuring *any* comparator interrupts.
+        */
        hd.hd_irq[0] = HPET_LEGACY_8254;
        hd.hd_irq[1] = HPET_LEGACY_RTC;
 
index 1f26fd9ec4f4ea101c69ee030ac4142f4458d5ae..5b5be9d43c2a865fdcbe1ac0f689e750f5e6f5de 100644 (file)
@@ -135,7 +135,7 @@ DEFINE_PER_CPU(vector_irq_t, vector_irq) = {
        [IRQ15_VECTOR + 1 ... NR_VECTORS - 1] = -1
 };
 
-static void __init init_ISA_irqs (void)
+void __init init_ISA_irqs(void)
 {
        int i;
 
@@ -164,22 +164,8 @@ static void __init init_ISA_irqs (void)
 
 void init_IRQ(void) __attribute__((weak, alias("native_init_IRQ")));
 
-void __init native_init_IRQ(void)
+static void __init smp_intr_init(void)
 {
-       int i;
-
-       init_ISA_irqs();
-       /*
-        * Cover the whole vector space, no vector can escape
-        * us. (some of these will be overridden and become
-        * 'special' SMP interrupts)
-        */
-       for (i = 0; i < (NR_VECTORS - FIRST_EXTERNAL_VECTOR); i++) {
-               int vector = FIRST_EXTERNAL_VECTOR + i;
-               if (vector != IA32_SYSCALL_VECTOR)
-                       set_intr_gate(vector, interrupt[i]);
-       }
-
 #ifdef CONFIG_SMP
        /*
         * The reschedule interrupt is a CPU-to-CPU reschedule-helper
@@ -207,6 +193,12 @@ void __init native_init_IRQ(void)
        /* Low priority IPI to cleanup after moving an irq */
        set_intr_gate(IRQ_MOVE_CLEANUP_VECTOR, irq_move_cleanup_interrupt);
 #endif
+}
+
+static void __init apic_intr_init(void)
+{
+       smp_intr_init();
+
        alloc_intr_gate(THERMAL_APIC_VECTOR, thermal_interrupt);
        alloc_intr_gate(THRESHOLD_APIC_VECTOR, threshold_interrupt);
 
@@ -216,6 +208,25 @@ void __init native_init_IRQ(void)
        /* IPI vectors for APIC spurious and error interrupts */
        alloc_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt);
        alloc_intr_gate(ERROR_APIC_VECTOR, error_interrupt);
+}
+
+void __init native_init_IRQ(void)
+{
+       int i;
+
+       init_ISA_irqs();
+       /*
+        * Cover the whole vector space, no vector can escape
+        * us. (some of these will be overridden and become
+        * 'special' SMP interrupts)
+        */
+       for (i = 0; i < (NR_VECTORS - FIRST_EXTERNAL_VECTOR); i++) {
+               int vector = FIRST_EXTERNAL_VECTOR + i;
+               if (vector != IA32_SYSCALL_VECTOR)
+                       set_intr_gate(vector, interrupt[i]);
+       }
+
+       apic_intr_init();
 
        if (!acpi_ioapic)
                setup_irq(2, &irq2);
index 922c14058f975d92cbb51d764d8a84256ad9f3fb..0a1302fe6d45307ffa880ed9e355050a194518af 100644 (file)
@@ -123,7 +123,7 @@ void cpu_idle(void)
        }
 }
 
-void __show_registers(struct pt_regs *regs, int all)
+void __show_regs(struct pt_regs *regs, int all)
 {
        unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L;
        unsigned long d0, d1, d2, d3, d6, d7;
@@ -189,7 +189,7 @@ void __show_registers(struct pt_regs *regs, int all)
 
 void show_regs(struct pt_regs *regs)
 {
-       __show_registers(regs, 1);
+       __show_regs(regs, 1);
        show_trace(NULL, regs, &regs->sp, regs->bp);
 }
 
index ca80394ef5b80ebff3fb5fad35aec9d683a8b32c..cd8c0ed02b7e2c017905a403f10fc3cd25413f4a 100644 (file)
@@ -136,7 +136,7 @@ void cpu_idle(void)
 }
 
 /* Prints also some state that isn't saved in the pt_regs */
-void __show_regs(struct pt_regs *regs)
+void __show_regs(struct pt_regs *regs, int all)
 {
        unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L, fs, gs, shadowgs;
        unsigned long d0, d1, d2, d3, d6, d7;
@@ -175,6 +175,9 @@ void __show_regs(struct pt_regs *regs)
        rdmsrl(MSR_GS_BASE, gs);
        rdmsrl(MSR_KERNEL_GS_BASE, shadowgs);
 
+       if (!all)
+               return;
+
        cr0 = read_cr0();
        cr2 = read_cr2();
        cr3 = read_cr3();
@@ -200,7 +203,7 @@ void __show_regs(struct pt_regs *regs)
 void show_regs(struct pt_regs *regs)
 {
        printk(KERN_INFO "CPU %d:", smp_processor_id());
-       __show_regs(regs);
+       __show_regs(regs, 1);
        show_trace(NULL, regs, (void *)(regs + 1), regs->bp);
 }
 
index d13858818100e6f35cb328bab4394dc00885d712..f6a11b9b1f9887f8979e67c982c5c5a39b3e1915 100644 (file)
@@ -354,9 +354,27 @@ static void ati_force_hpet_resume(void)
        printk(KERN_DEBUG "Force enabled HPET at resume\n");
 }
 
+static u32 ati_ixp4x0_rev(struct pci_dev *dev)
+{
+       u32 d;
+       u8  b;
+
+       pci_read_config_byte(dev, 0xac, &b);
+       b &= ~(1<<5);
+       pci_write_config_byte(dev, 0xac, b);
+       pci_read_config_dword(dev, 0x70, &d);
+       d |= 1<<8;
+       pci_write_config_dword(dev, 0x70, d);
+       pci_read_config_dword(dev, 0x8, &d);
+       d &= 0xff;
+       dev_printk(KERN_DEBUG, &dev->dev, "SB4X0 revision 0x%x\n", d);
+       return d;
+}
+
 static void ati_force_enable_hpet(struct pci_dev *dev)
 {
-       u32 uninitialized_var(val);
+       u32 d, val;
+       u8  b;
 
        if (hpet_address || force_hpet_address)
                return;
@@ -366,14 +384,33 @@ static void ati_force_enable_hpet(struct pci_dev *dev)
                return;
        }
 
+       d = ati_ixp4x0_rev(dev);
+       if (d  < 0x82)
+               return;
+
+       /* base address */
        pci_write_config_dword(dev, 0x14, 0xfed00000);
        pci_read_config_dword(dev, 0x14, &val);
+
+       /* enable interrupt */
+       outb(0x72, 0xcd6); b = inb(0xcd7);
+       b |= 0x1;
+       outb(0x72, 0xcd6); outb(b, 0xcd7);
+       outb(0x72, 0xcd6); b = inb(0xcd7);
+       if (!(b & 0x1))
+               return;
+       pci_read_config_dword(dev, 0x64, &d);
+       d |= (1<<10);
+       pci_write_config_dword(dev, 0x64, d);
+       pci_read_config_dword(dev, 0x64, &d);
+       if (!(d & (1<<10)))
+               return;
+
        force_hpet_address = val;
        force_hpet_resume_type = ATI_FORCE_HPET_RESUME;
        dev_printk(KERN_DEBUG, &dev->dev, "Force enabled HPET at 0x%lx\n",
                   force_hpet_address);
        cached_dev = dev;
-       return;
 }
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_SMBUS,
                         ati_force_enable_hpet);
index 21b8e0a59780105c673813c9500207758b1def7a..2255782e8d4b94664ff8c3c053af26aa114d0e6c 100644 (file)
@@ -302,7 +302,7 @@ static void __init relocate_initrd(void)
                if (clen > MAX_MAP_CHUNK-slop)
                        clen = MAX_MAP_CHUNK-slop;
                mapaddr = ramdisk_image & PAGE_MASK;
-               p = early_ioremap(mapaddr, clen+slop);
+               p = early_memremap(mapaddr, clen+slop);
                memcpy(q, p+slop, clen);
                early_iounmap(p, clen+slop);
                q += clen;
@@ -379,7 +379,7 @@ static void __init parse_setup_data(void)
                return;
        pa_data = boot_params.hdr.setup_data;
        while (pa_data) {
-               data = early_ioremap(pa_data, PAGE_SIZE);
+               data = early_memremap(pa_data, PAGE_SIZE);
                switch (data->type) {
                case SETUP_E820_EXT:
                        parse_e820_ext(data, pa_data);
@@ -402,7 +402,7 @@ static void __init e820_reserve_setup_data(void)
                return;
        pa_data = boot_params.hdr.setup_data;
        while (pa_data) {
-               data = early_ioremap(pa_data, sizeof(*data));
+               data = early_memremap(pa_data, sizeof(*data));
                e820_update_range(pa_data, sizeof(*data)+data->len,
                         E820_RAM, E820_RESERVED_KERN);
                found = 1;
@@ -428,7 +428,7 @@ static void __init reserve_early_setup_data(void)
                return;
        pa_data = boot_params.hdr.setup_data;
        while (pa_data) {
-               data = early_ioremap(pa_data, sizeof(*data));
+               data = early_memremap(pa_data, sizeof(*data));
                sprintf(buf, "setup data %x", data->type);
                reserve_early(pa_data, pa_data+sizeof(*data)+data->len, buf);
                pa_data = data->next;
@@ -998,6 +998,8 @@ void __init setup_arch(char **cmdline_p)
         */
        acpi_boot_table_init();
 
+       early_acpi_boot_init();
+
 #ifdef CONFIG_ACPI_NUMA
        /*
         * Parse SRAT to discover nodes.
index 76b6f50978f7f7219125ffb05b55fa1fd4f273a0..8c3aca7cb343fb4d1cc93bf8e447b04b19839ff7 100644 (file)
@@ -334,14 +334,17 @@ static void __cpuinit start_secondary(void *unused)
         * does not change while we are assigning vectors to cpus.  Holding
         * this lock ensures we don't half assign or remove an irq from a cpu.
         */
-       ipi_call_lock_irq();
+       ipi_call_lock();
        lock_vector_lock();
        __setup_vector_irq(smp_processor_id());
        cpu_set(smp_processor_id(), cpu_online_map);
        unlock_vector_lock();
-       ipi_call_unlock_irq();
+       ipi_call_unlock();
        per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE;
 
+       /* enable local interrupts */
+       local_irq_enable();
+
        setup_secondary_clock();
 
        wmb();
@@ -596,10 +599,12 @@ wakeup_secondary_cpu(int logical_apicid, unsigned long start_eip)
         * Give the other CPU some time to accept the IPI.
         */
        udelay(200);
-       maxlvt = lapic_get_maxlvt();
-       if (maxlvt > 3)                 /* Due to the Pentium erratum 3AP.  */
-               apic_write(APIC_ESR, 0);
-       accept_status = (apic_read(APIC_ESR) & 0xEF);
+       if (APIC_INTEGRATED(apic_version[phys_apicid])) {
+               maxlvt = lapic_get_maxlvt();
+               if (maxlvt > 3)                 /* Due to the Pentium erratum 3AP.  */
+                       apic_write(APIC_ESR, 0);
+               accept_status = (apic_read(APIC_ESR) & 0xEF);
+       }
        pr_debug("NMI sent.\n");
 
        if (send_status)
@@ -1256,39 +1261,6 @@ void __init native_smp_cpus_done(unsigned int max_cpus)
        check_nmi_watchdog();
 }
 
-#ifdef CONFIG_HOTPLUG_CPU
-
-static void remove_siblinginfo(int cpu)
-{
-       int sibling;
-       struct cpuinfo_x86 *c = &cpu_data(cpu);
-
-       for_each_cpu_mask_nr(sibling, per_cpu(cpu_core_map, cpu)) {
-               cpu_clear(cpu, per_cpu(cpu_core_map, sibling));
-               /*/
-                * last thread sibling in this cpu core going down
-                */
-               if (cpus_weight(per_cpu(cpu_sibling_map, cpu)) == 1)
-                       cpu_data(sibling).booted_cores--;
-       }
-
-       for_each_cpu_mask_nr(sibling, per_cpu(cpu_sibling_map, cpu))
-               cpu_clear(cpu, per_cpu(cpu_sibling_map, sibling));
-       cpus_clear(per_cpu(cpu_sibling_map, cpu));
-       cpus_clear(per_cpu(cpu_core_map, cpu));
-       c->phys_proc_id = 0;
-       c->cpu_core_id = 0;
-       cpu_clear(cpu, cpu_sibling_setup_map);
-}
-
-static int additional_cpus __initdata = -1;
-
-static __init int setup_additional_cpus(char *s)
-{
-       return s && get_option(&s, &additional_cpus) ? 0 : -EINVAL;
-}
-early_param("additional_cpus", setup_additional_cpus);
-
 /*
  * cpu_possible_map should be static, it cannot change as cpu's
  * are onlined, or offlined. The reason is per-cpu data-structures
@@ -1308,21 +1280,13 @@ early_param("additional_cpus", setup_additional_cpus);
  */
 __init void prefill_possible_map(void)
 {
-       int i;
-       int possible;
+       int i, possible;
 
        /* no processor from mptable or madt */
        if (!num_processors)
                num_processors = 1;
 
-       if (additional_cpus == -1) {
-               if (disabled_cpus > 0)
-                       additional_cpus = disabled_cpus;
-               else
-                       additional_cpus = 0;
-       }
-
-       possible = num_processors + additional_cpus;
+       possible = num_processors + disabled_cpus;
        if (possible > NR_CPUS)
                possible = NR_CPUS;
 
@@ -1335,6 +1299,31 @@ __init void prefill_possible_map(void)
        nr_cpu_ids = possible;
 }
 
+#ifdef CONFIG_HOTPLUG_CPU
+
+static void remove_siblinginfo(int cpu)
+{
+       int sibling;
+       struct cpuinfo_x86 *c = &cpu_data(cpu);
+
+       for_each_cpu_mask_nr(sibling, per_cpu(cpu_core_map, cpu)) {
+               cpu_clear(cpu, per_cpu(cpu_core_map, sibling));
+               /*/
+                * last thread sibling in this cpu core going down
+                */
+               if (cpus_weight(per_cpu(cpu_sibling_map, cpu)) == 1)
+                       cpu_data(sibling).booted_cores--;
+       }
+
+       for_each_cpu_mask_nr(sibling, per_cpu(cpu_sibling_map, cpu))
+               cpu_clear(cpu, per_cpu(cpu_sibling_map, sibling));
+       cpus_clear(per_cpu(cpu_sibling_map, cpu));
+       cpus_clear(per_cpu(cpu_core_map, cpu));
+       c->phys_proc_id = 0;
+       c->cpu_core_id = 0;
+       cpu_clear(cpu, cpu_sibling_setup_map);
+}
+
 static void __ref remove_cpu_from_maps(int cpu)
 {
        cpu_clear(cpu, cpu_online_map);
index bbecf8b6bf96392de71968bdfd5da4b8aae006ad..77b400f06ea2335fa770fb3273ce5cd7e5820c18 100644 (file)
@@ -47,10 +47,9 @@ unsigned long profile_pc(struct pt_regs *regs)
        unsigned long pc = instruction_pointer(regs);
 
 #ifdef CONFIG_SMP
-       if (!v8086_mode(regs) && SEGMENT_IS_KERNEL_CODE(regs->cs) &&
-           in_lock_functions(pc)) {
+       if (!user_mode_vm(regs) && in_lock_functions(pc)) {
 #ifdef CONFIG_FRAME_POINTER
-               return *(unsigned long *)(regs->bp + 4);
+               return *(unsigned long *)(regs->bp + sizeof(long));
 #else
                unsigned long *sp = (unsigned long *)&regs->sp;
 
@@ -95,6 +94,7 @@ irqreturn_t timer_interrupt(int irq, void *dev_id)
 
        do_timer_interrupt_hook();
 
+#ifdef CONFIG_MCA
        if (MCA_bus) {
                /* The PS/2 uses level-triggered interrupts.  You can't
                turn them off, nor would you want to (any attempt to
@@ -108,6 +108,7 @@ irqreturn_t timer_interrupt(int irq, void *dev_id)
                u8 irq_v = inb_p( 0x61 );       /* read the current state */
                outb_p( irq_v|0x80, 0x61 );     /* reset the IRQ */
        }
+#endif
 
        return IRQ_HANDLED;
 }
index e3d49c553af22aec7c773006b7018325dccb6ec0..cb19d650c21643599aa1423a57b64a85ee26afe8 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/time.h>
+#include <linux/mca.h>
 
 #include <asm/i8253.h>
 #include <asm/hpet.h>
@@ -33,23 +34,34 @@ unsigned long profile_pc(struct pt_regs *regs)
        /* Assume the lock function has either no stack frame or a copy
           of flags from PUSHF
           Eflags always has bits 22 and up cleared unlike kernel addresses. */
-       if (!user_mode(regs) && in_lock_functions(pc)) {
+       if (!user_mode_vm(regs) && in_lock_functions(pc)) {
+#ifdef CONFIG_FRAME_POINTER
+               return *(unsigned long *)(regs->bp + sizeof(long));
+#else
                unsigned long *sp = (unsigned long *)regs->sp;
                if (sp[0] >> 22)
                        return sp[0];
                if (sp[1] >> 22)
                        return sp[1];
+#endif
        }
        return pc;
 }
 EXPORT_SYMBOL(profile_pc);
 
-static irqreturn_t timer_event_interrupt(int irq, void *dev_id)
+irqreturn_t timer_interrupt(int irq, void *dev_id)
 {
        add_pda(irq0_irqs, 1);
 
        global_clock_event->event_handler(global_clock_event);
 
+#ifdef CONFIG_MCA
+       if (MCA_bus) {
+               u8 irq_v = inb_p(0x61);       /* read the current state */
+               outb_p(irq_v|0x80, 0x61);     /* reset the IRQ */
+       }
+#endif
+
        return IRQ_HANDLED;
 }
 
@@ -100,7 +112,7 @@ unsigned long __init calibrate_cpu(void)
 }
 
 static struct irqaction irq0 = {
-       .handler        = timer_event_interrupt,
+       .handler        = timer_interrupt,
        .flags          = IRQF_DISABLED | IRQF_IRQPOLL | IRQF_NOBALANCING,
        .mask           = CPU_MASK_NONE,
        .name           = "timer"
@@ -111,16 +123,13 @@ void __init hpet_time_init(void)
        if (!hpet_enable())
                setup_pit_timer();
 
+       irq0.mask = cpumask_of_cpu(0);
        setup_irq(0, &irq0);
 }
 
 void __init time_init(void)
 {
        tsc_init();
-       if (cpu_has(&boot_cpu_data, X86_FEATURE_RDTSCP))
-               vgetcpu_mode = VGETCPU_RDTSCP;
-       else
-               vgetcpu_mode = VGETCPU_LSL;
 
        late_time_init = choose_time_init();
 }
similarity index 57%
rename from arch/x86/kernel/traps_32.c
rename to arch/x86/kernel/traps.c
index 0429c5de5ea98d9e94a4401798a1de14ceff7394..e062974cce34265bc9f20857e3e4996c62c153c9 100644 (file)
@@ -7,13 +7,11 @@
  */
 
 /*
- * 'Traps.c' handles hardware traps and faults after we have saved some
- * state in 'asm.s'.
+ * Handle hardware traps and faults.
  */
 #include <linux/interrupt.h>
 #include <linux/kallsyms.h>
 #include <linux/spinlock.h>
-#include <linux/highmem.h>
 #include <linux/kprobes.h>
 #include <linux/uaccess.h>
 #include <linux/utsname.h>
@@ -32,6 +30,8 @@
 #include <linux/bug.h>
 #include <linux/nmi.h>
 #include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/io.h>
 
 #ifdef CONFIG_EISA
 #include <linux/ioport.h>
 #include <linux/edac.h>
 #endif
 
-#include <asm/arch_hooks.h>
 #include <asm/stacktrace.h>
 #include <asm/processor.h>
 #include <asm/debugreg.h>
 #include <asm/atomic.h>
 #include <asm/system.h>
 #include <asm/unwind.h>
+#include <asm/traps.h>
 #include <asm/desc.h>
 #include <asm/i387.h>
+
+#include <mach_traps.h>
+
+#ifdef CONFIG_X86_64
+#include <asm/pgalloc.h>
+#include <asm/proto.h>
+#include <asm/pda.h>
+#else
+#include <asm/processor-flags.h>
+#include <asm/arch_hooks.h>
 #include <asm/nmi.h>
 #include <asm/smp.h>
 #include <asm/io.h>
 #include <asm/traps.h>
 
-#include "mach_traps.h"
+#include "cpu/mcheck/mce.h"
 
 DECLARE_BITMAP(used_vectors, NR_VECTORS);
 EXPORT_SYMBOL_GPL(used_vectors);
@@ -77,418 +87,104 @@ char ignore_fpu_irq;
  */
 gate_desc idt_table[256]
        __attribute__((__section__(".data.idt"))) = { { { { 0, 0 } } }, };
-
-int panic_on_unrecovered_nmi;
-int kstack_depth_to_print = 24;
-static unsigned int code_bytes = 64;
-static int ignore_nmis;
-static int die_counter;
-
-void printk_address(unsigned long address, int reliable)
-{
-#ifdef CONFIG_KALLSYMS
-       unsigned long offset = 0;
-       unsigned long symsize;
-       const char *symname;
-       char *modname;
-       char *delim = ":";
-       char namebuf[KSYM_NAME_LEN];
-       char reliab[4] = "";
-
-       symname = kallsyms_lookup(address, &symsize, &offset,
-                                       &modname, namebuf);
-       if (!symname) {
-               printk(" [<%08lx>]\n", address);
-               return;
-       }
-       if (!reliable)
-               strcpy(reliab, "? ");
-
-       if (!modname)
-               modname = delim = "";
-       printk(" [<%08lx>] %s%s%s%s%s+0x%lx/0x%lx\n",
-               address, reliab, delim, modname, delim, symname, offset, symsize);
-#else
-       printk(" [<%08lx>]\n", address);
 #endif
-}
-
-static inline int valid_stack_ptr(struct thread_info *tinfo,
-                       void *p, unsigned int size)
-{
-       void *t = tinfo;
-       return  p > t && p <= t + THREAD_SIZE - size;
-}
-
-/* The form of the top of the frame on the stack */
-struct stack_frame {
-       struct stack_frame *next_frame;
-       unsigned long return_address;
-};
-
-static inline unsigned long
-print_context_stack(struct thread_info *tinfo,
-               unsigned long *stack, unsigned long bp,
-               const struct stacktrace_ops *ops, void *data)
-{
-       struct stack_frame *frame = (struct stack_frame *)bp;
-
-       while (valid_stack_ptr(tinfo, stack, sizeof(*stack))) {
-               unsigned long addr;
-
-               addr = *stack;
-               if (__kernel_text_address(addr)) {
-                       if ((unsigned long) stack == bp + 4) {
-                               ops->address(data, addr, 1);
-                               frame = frame->next_frame;
-                               bp = (unsigned long) frame;
-                       } else {
-                               ops->address(data, addr, bp == 0);
-                       }
-               }
-               stack++;
-       }
-       return bp;
-}
-
-void dump_trace(struct task_struct *task, struct pt_regs *regs,
-               unsigned long *stack, unsigned long bp,
-               const struct stacktrace_ops *ops, void *data)
-{
-       if (!task)
-               task = current;
-
-       if (!stack) {
-               unsigned long dummy;
-               stack = &dummy;
-               if (task != current)
-                       stack = (unsigned long *)task->thread.sp;
-       }
-
-#ifdef CONFIG_FRAME_POINTER
-       if (!bp) {
-               if (task == current) {
-                       /* Grab bp right from our regs */
-                       asm("movl %%ebp, %0" : "=r" (bp) :);
-               } else {
-                       /* bp is the last reg pushed by switch_to */
-                       bp = *(unsigned long *) task->thread.sp;
-               }
-       }
-#endif
-
-       for (;;) {
-               struct thread_info *context;
-
-               context = (struct thread_info *)
-                       ((unsigned long)stack & (~(THREAD_SIZE - 1)));
-               bp = print_context_stack(context, stack, bp, ops, data);
-               /*
-                * Should be after the line below, but somewhere
-                * in early boot context comes out corrupted and we
-                * can't reference it:
-                */
-               if (ops->stack(data, "IRQ") < 0)
-                       break;
-               stack = (unsigned long *)context->previous_esp;
-               if (!stack)
-                       break;
-               touch_nmi_watchdog();
-       }
-}
-EXPORT_SYMBOL(dump_trace);
-
-static void
-print_trace_warning_symbol(void *data, char *msg, unsigned long symbol)
-{
-       printk(data);
-       print_symbol(msg, symbol);
-       printk("\n");
-}
-
-static void print_trace_warning(void *data, char *msg)
-{
-       printk("%s%s\n", (char *)data, msg);
-}
 
-static int print_trace_stack(void *data, char *name)
-{
-       return 0;
-}
-
-/*
- * Print one address/symbol entries per line.
- */
-static void print_trace_address(void *data, unsigned long addr, int reliable)
-{
-       printk("%s [<%08lx>] ", (char *)data, addr);
-       if (!reliable)
-               printk("? ");
-       print_symbol("%s\n", addr);
-       touch_nmi_watchdog();
-}
-
-static const struct stacktrace_ops print_trace_ops = {
-       .warning = print_trace_warning,
-       .warning_symbol = print_trace_warning_symbol,
-       .stack = print_trace_stack,
-       .address = print_trace_address,
-};
+static int ignore_nmis;
 
-static void
-show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs,
-               unsigned long *stack, unsigned long bp, char *log_lvl)
+static inline void conditional_sti(struct pt_regs *regs)
 {
-       dump_trace(task, regs, stack, bp, &print_trace_ops, log_lvl);
-       printk("%s =======================\n", log_lvl);
+       if (regs->flags & X86_EFLAGS_IF)
+               local_irq_enable();
 }
 
-void show_trace(struct task_struct *task, struct pt_regs *regs,
-               unsigned long *stack, unsigned long bp)
+static inline void preempt_conditional_sti(struct pt_regs *regs)
 {
-       show_trace_log_lvl(task, regs, stack, bp, "");
+       inc_preempt_count();
+       if (regs->flags & X86_EFLAGS_IF)
+               local_irq_enable();
 }
 
-static void
-show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
-                  unsigned long *sp, unsigned long bp, char *log_lvl)
+static inline void preempt_conditional_cli(struct pt_regs *regs)
 {
-       unsigned long *stack;
-       int i;
-
-       if (sp == NULL) {
-               if (task)
-                       sp = (unsigned long *)task->thread.sp;
-               else
-                       sp = (unsigned long *)&sp;
-       }
-
-       stack = sp;
-       for (i = 0; i < kstack_depth_to_print; i++) {
-               if (kstack_end(stack))
-                       break;
-               if (i && ((i % 8) == 0))
-                       printk("\n%s       ", log_lvl);
-               printk("%08lx ", *stack++);
-       }
-       printk("\n%sCall Trace:\n", log_lvl);
-
-       show_trace_log_lvl(task, regs, sp, bp, log_lvl);
+       if (regs->flags & X86_EFLAGS_IF)
+               local_irq_disable();
+       dec_preempt_count();
 }
 
-void show_stack(struct task_struct *task, unsigned long *sp)
+#ifdef CONFIG_X86_32
+static inline void
+die_if_kernel(const char *str, struct pt_regs *regs, long err)
 {
-       printk("       ");
-       show_stack_log_lvl(task, NULL, sp, 0, "");
+       if (!user_mode_vm(regs))
+               die(str, regs, err);
 }
 
 /*
- * The architecture-independent dump_stack generator
+ * Perform the lazy TSS's I/O bitmap copy. If the TSS has an
+ * invalid offset set (the LAZY one) and the faulting thread has
+ * a valid I/O bitmap pointer, we copy the I/O bitmap in the TSS,
+ * we set the offset field correctly and return 1.
  */
-void dump_stack(void)
+static int lazy_iobitmap_copy(void)
 {
-       unsigned long bp = 0;
-       unsigned long stack;
-
-#ifdef CONFIG_FRAME_POINTER
-       if (!bp)
-               asm("movl %%ebp, %0" : "=r" (bp):);
-#endif
-
-       printk("Pid: %d, comm: %.20s %s %s %.*s\n",
-               current->pid, current->comm, print_tainted(),
-               init_utsname()->release,
-               (int)strcspn(init_utsname()->version, " "),
-               init_utsname()->version);
-
-       show_trace(current, NULL, &stack, bp);
-}
-
-EXPORT_SYMBOL(dump_stack);
-
-void show_registers(struct pt_regs *regs)
-{
-       int i;
+       struct thread_struct *thread;
+       struct tss_struct *tss;
+       int cpu;
 
-       print_modules();
-       __show_registers(regs, 0);
+       cpu = get_cpu();
+       tss = &per_cpu(init_tss, cpu);
+       thread = &current->thread;
 
-       printk(KERN_EMERG "Process %.*s (pid: %d, ti=%p task=%p task.ti=%p)",
-               TASK_COMM_LEN, current->comm, task_pid_nr(current),
-               current_thread_info(), current, task_thread_info(current));
-       /*
-        * When in-kernel, we also print out the stack and code at the
-        * time of the fault..
-        */
-       if (!user_mode_vm(regs)) {
-               unsigned int code_prologue = code_bytes * 43 / 64;
-               unsigned int code_len = code_bytes;
-               unsigned char c;
-               u8 *ip;
-
-               printk("\n" KERN_EMERG "Stack: ");
-               show_stack_log_lvl(NULL, regs, &regs->sp, 0, KERN_EMERG);
-
-               printk(KERN_EMERG "Code: ");
-
-               ip = (u8 *)regs->ip - code_prologue;
-               if (ip < (u8 *)PAGE_OFFSET || probe_kernel_address(ip, c)) {
-                       /* try starting at EIP */
-                       ip = (u8 *)regs->ip;
-                       code_len = code_len - code_prologue + 1;
-               }
-               for (i = 0; i < code_len; i++, ip++) {
-                       if (ip < (u8 *)PAGE_OFFSET ||
-                                       probe_kernel_address(ip, c)) {
-                               printk(" Bad EIP value.");
-                               break;
-                       }
-                       if (ip == (u8 *)regs->ip)
-                               printk("<%02x> ", c);
-                       else
-                               printk("%02x ", c);
+       if (tss->x86_tss.io_bitmap_base == INVALID_IO_BITMAP_OFFSET_LAZY &&
+           thread->io_bitmap_ptr) {
+               memcpy(tss->io_bitmap, thread->io_bitmap_ptr,
+                      thread->io_bitmap_max);
+               /*
+                * If the previously set map was extending to higher ports
+                * than the current one, pad extra space with 0xff (no access).
+                */
+               if (thread->io_bitmap_max < tss->io_bitmap_max) {
+                       memset((char *) tss->io_bitmap +
+                               thread->io_bitmap_max, 0xff,
+                               tss->io_bitmap_max - thread->io_bitmap_max);
                }
-       }
-       printk("\n");
-}
-
-int is_valid_bugaddr(unsigned long ip)
-{
-       unsigned short ud2;
-
-       if (ip < PAGE_OFFSET)
-               return 0;
-       if (probe_kernel_address((unsigned short *)ip, ud2))
-               return 0;
-
-       return ud2 == 0x0b0f;
-}
-
-static raw_spinlock_t die_lock = __RAW_SPIN_LOCK_UNLOCKED;
-static int die_owner = -1;
-static unsigned int die_nest_count;
-
-unsigned __kprobes long oops_begin(void)
-{
-       unsigned long flags;
-
-       oops_enter();
-
-       if (die_owner != raw_smp_processor_id()) {
-               console_verbose();
-               raw_local_irq_save(flags);
-               __raw_spin_lock(&die_lock);
-               die_owner = smp_processor_id();
-               die_nest_count = 0;
-               bust_spinlocks(1);
-       } else {
-               raw_local_irq_save(flags);
-       }
-       die_nest_count++;
-       return flags;
-}
-
-void __kprobes oops_end(unsigned long flags, struct pt_regs *regs, int signr)
-{
-       bust_spinlocks(0);
-       die_owner = -1;
-       add_taint(TAINT_DIE);
-       __raw_spin_unlock(&die_lock);
-       raw_local_irq_restore(flags);
-
-       if (!regs)
-               return;
-
-       if (kexec_should_crash(current))
-               crash_kexec(regs);
-
-       if (in_interrupt())
-               panic("Fatal exception in interrupt");
-
-       if (panic_on_oops)
-               panic("Fatal exception");
-
-       oops_exit();
-       do_exit(signr);
-}
-
-int __kprobes __die(const char *str, struct pt_regs *regs, long err)
-{
-       unsigned short ss;
-       unsigned long sp;
+               tss->io_bitmap_max = thread->io_bitmap_max;
+               tss->x86_tss.io_bitmap_base = IO_BITMAP_OFFSET;
+               tss->io_bitmap_owner = thread;
+               put_cpu();
 
-       printk(KERN_EMERG "%s: %04lx [#%d] ", str, err & 0xffff, ++die_counter);
-#ifdef CONFIG_PREEMPT
-       printk("PREEMPT ");
-#endif
-#ifdef CONFIG_SMP
-       printk("SMP ");
-#endif
-#ifdef CONFIG_DEBUG_PAGEALLOC
-       printk("DEBUG_PAGEALLOC");
-#endif
-       printk("\n");
-       if (notify_die(DIE_OOPS, str, regs, err,
-                       current->thread.trap_no, SIGSEGV) == NOTIFY_STOP)
                return 1;
-
-       show_registers(regs);
-       /* Executive summary in case the oops scrolled away */
-       sp = (unsigned long) (&regs->sp);
-       savesegment(ss, ss);
-       if (user_mode(regs)) {
-               sp = regs->sp;
-               ss = regs->ss & 0xffff;
        }
-       printk(KERN_EMERG "EIP: [<%08lx>] ", regs->ip);
-       print_symbol("%s", regs->ip);
-       printk(" SS:ESP %04x:%08lx\n", ss, sp);
-       return 0;
-}
-
-/*
- * This is gone through when something in the kernel has done something bad
- * and is about to be terminated:
- */
-void die(const char *str, struct pt_regs *regs, long err)
-{
-       unsigned long flags = oops_begin();
-
-       if (die_nest_count < 3) {
-               report_bug(regs->ip, regs);
-
-               if (__die(str, regs, err))
-                       regs = NULL;
-       } else {
-               printk(KERN_EMERG "Recursive die() failure, output suppressed\n");
-       }
-
-       oops_end(flags, regs, SIGSEGV);
-}
+       put_cpu();
 
-static inline void
-die_if_kernel(const char *str, struct pt_regs *regs, long err)
-{
-       if (!user_mode_vm(regs))
-               die(str, regs, err);
+       return 0;
 }
+#endif
 
 static void __kprobes
-do_trap(int trapnr, int signr, char *str, int vm86, struct pt_regs *regs,
+do_trap(int trapnr, int signr, char *str, struct pt_regs *regs,
        long error_code, siginfo_t *info)
 {
        struct task_struct *tsk = current;
 
+#ifdef CONFIG_X86_32
        if (regs->flags & X86_VM_MASK) {
-               if (vm86)
+               /*
+                * traps 0, 1, 3, 4, and 5 should be forwarded to vm86.
+                * On nmi (interrupt 2), do_trap should not be called.
+                */
+               if (trapnr < 6)
                        goto vm86_trap;
                goto trap_signal;
        }
+#endif
 
        if (!user_mode(regs))
                goto kernel_trap;
 
+#ifdef CONFIG_X86_32
 trap_signal:
+#endif
        /*
         * We want error_code and trap_no set for userspace faults and
         * kernelspace faults which result in die(), but not
@@ -501,6 +197,18 @@ trap_signal:
        tsk->thread.error_code = error_code;
        tsk->thread.trap_no = trapnr;
 
+#ifdef CONFIG_X86_64
+       if (show_unhandled_signals && unhandled_signal(tsk, signr) &&
+           printk_ratelimit()) {
+               printk(KERN_INFO
+                      "%s[%d] trap %s ip:%lx sp:%lx error:%lx",
+                      tsk->comm, tsk->pid, str,
+                      regs->ip, regs->sp, error_code);
+               print_vma_addr(" in ", regs->ip);
+               printk("\n");
+       }
+#endif
+
        if (info)
                force_sig_info(signr, info, tsk);
        else
@@ -515,29 +223,29 @@ kernel_trap:
        }
        return;
 
+#ifdef CONFIG_X86_32
 vm86_trap:
        if (handle_vm86_trap((struct kernel_vm86_regs *) regs,
                                                error_code, trapnr))
                goto trap_signal;
        return;
+#endif
 }
 
 #define DO_ERROR(trapnr, signr, str, name)                             \
-void do_##name(struct pt_regs *regs, long error_code)                  \
+dotraplinkage void do_##name(struct pt_regs *regs, long error_code)    \
 {                                                                      \
-       trace_hardirqs_fixup();                                         \
        if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr)  \
                                                        == NOTIFY_STOP) \
                return;                                                 \
-       do_trap(trapnr, signr, str, 0, regs, error_code, NULL);         \
+       conditional_sti(regs);                                          \
+       do_trap(trapnr, signr, str, regs, error_code, NULL);            \
 }
 
-#define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr, irq)   \
-void do_##name(struct pt_regs *regs, long error_code)                  \
+#define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr)                \
+dotraplinkage void do_##name(struct pt_regs *regs, long error_code)    \
 {                                                                      \
        siginfo_t info;                                                 \
-       if (irq)                                                        \
-               local_irq_enable();                                     \
        info.si_signo = signr;                                          \
        info.si_errno = 0;                                              \
        info.si_code = sicode;                                          \
@@ -545,90 +253,68 @@ void do_##name(struct pt_regs *regs, long error_code)                     \
        if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr)  \
                                                        == NOTIFY_STOP) \
                return;                                                 \
-       do_trap(trapnr, signr, str, 0, regs, error_code, &info);        \
+       conditional_sti(regs);                                          \
+       do_trap(trapnr, signr, str, regs, error_code, &info);           \
 }
 
-#define DO_VM86_ERROR(trapnr, signr, str, name)                                \
-void do_##name(struct pt_regs *regs, long error_code)                  \
-{                                                                      \
-       if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr)  \
-                                                       == NOTIFY_STOP) \
-               return;                                                 \
-       do_trap(trapnr, signr, str, 1, regs, error_code, NULL);         \
-}
-
-#define DO_VM86_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr)   \
-void do_##name(struct pt_regs *regs, long error_code)                  \
-{                                                                      \
-       siginfo_t info;                                                 \
-       info.si_signo = signr;                                          \
-       info.si_errno = 0;                                              \
-       info.si_code = sicode;                                          \
-       info.si_addr = (void __user *)siaddr;                           \
-       trace_hardirqs_fixup();                                         \
-       if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr)  \
-                                                       == NOTIFY_STOP) \
-               return;                                                 \
-       do_trap(trapnr, signr, str, 1, regs, error_code, &info);        \
-}
-
-DO_VM86_ERROR_INFO(0, SIGFPE, "divide error", divide_error, FPE_INTDIV, regs->ip)
-#ifndef CONFIG_KPROBES
-DO_VM86_ERROR(3, SIGTRAP, "int3", int3)
-#endif
-DO_VM86_ERROR(4, SIGSEGV, "overflow", overflow)
-DO_VM86_ERROR(5, SIGSEGV, "bounds", bounds)
-DO_ERROR_INFO(6, SIGILL, "invalid opcode", invalid_op, ILL_ILLOPN, regs->ip, 0)
+DO_ERROR_INFO(0, SIGFPE, "divide error", divide_error, FPE_INTDIV, regs->ip)
+DO_ERROR(4, SIGSEGV, "overflow", overflow)
+DO_ERROR(5, SIGSEGV, "bounds", bounds)
+DO_ERROR_INFO(6, SIGILL, "invalid opcode", invalid_op, ILL_ILLOPN, regs->ip)
 DO_ERROR(9, SIGFPE, "coprocessor segment overrun", coprocessor_segment_overrun)
 DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS)
 DO_ERROR(11, SIGBUS, "segment not present", segment_not_present)
+#ifdef CONFIG_X86_32
 DO_ERROR(12, SIGBUS, "stack segment", stack_segment)
-DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0, 0)
-DO_ERROR_INFO(32, SIGILL, "iret exception", iret_error, ILL_BADSTK, 0, 1)
+#endif
+DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0)
+
+#ifdef CONFIG_X86_64
+/* Runs on IST stack */
+dotraplinkage void do_stack_segment(struct pt_regs *regs, long error_code)
+{
+       if (notify_die(DIE_TRAP, "stack segment", regs, error_code,
+                       12, SIGBUS) == NOTIFY_STOP)
+               return;
+       preempt_conditional_sti(regs);
+       do_trap(12, SIGBUS, "stack segment", regs, error_code, NULL);
+       preempt_conditional_cli(regs);
+}
+
+dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code)
+{
+       static const char str[] = "double fault";
+       struct task_struct *tsk = current;
+
+       /* Return not checked because double check cannot be ignored */
+       notify_die(DIE_TRAP, str, regs, error_code, 8, SIGSEGV);
 
-void __kprobes
+       tsk->thread.error_code = error_code;
+       tsk->thread.trap_no = 8;
+
+       /* This is always a kernel trap and never fixable (and thus must
+          never return). */
+       for (;;)
+               die(str, regs, error_code);
+}
+#endif
+
+dotraplinkage void __kprobes
 do_general_protection(struct pt_regs *regs, long error_code)
 {
        struct task_struct *tsk;
-       struct thread_struct *thread;
-       struct tss_struct *tss;
-       int cpu;
 
-       cpu = get_cpu();
-       tss = &per_cpu(init_tss, cpu);
-       thread = &current->thread;
-
-       /*
-        * Perform the lazy TSS's I/O bitmap copy. If the TSS has an
-        * invalid offset set (the LAZY one) and the faulting thread has
-        * a valid I/O bitmap pointer, we copy the I/O bitmap in the TSS
-        * and we set the offset field correctly. Then we let the CPU to
-        * restart the faulting instruction.
-        */
-       if (tss->x86_tss.io_bitmap_base == INVALID_IO_BITMAP_OFFSET_LAZY &&
-           thread->io_bitmap_ptr) {
-               memcpy(tss->io_bitmap, thread->io_bitmap_ptr,
-                      thread->io_bitmap_max);
-               /*
-                * If the previously set map was extending to higher ports
-                * than the current one, pad extra space with 0xff (no access).
-                */
-               if (thread->io_bitmap_max < tss->io_bitmap_max) {
-                       memset((char *) tss->io_bitmap +
-                               thread->io_bitmap_max, 0xff,
-                               tss->io_bitmap_max - thread->io_bitmap_max);
-               }
-               tss->io_bitmap_max = thread->io_bitmap_max;
-               tss->x86_tss.io_bitmap_base = IO_BITMAP_OFFSET;
-               tss->io_bitmap_owner = thread;
-               put_cpu();
+       conditional_sti(regs);
 
+#ifdef CONFIG_X86_32
+       if (lazy_iobitmap_copy()) {
+               /* restart the faulting instruction */
                return;
        }
-       put_cpu();
 
        if (regs->flags & X86_VM_MASK)
                goto gp_in_vm86;
+#endif
 
        tsk = current;
        if (!user_mode(regs))
@@ -650,10 +336,12 @@ do_general_protection(struct pt_regs *regs, long error_code)
        force_sig(SIGSEGV, tsk);
        return;
 
+#ifdef CONFIG_X86_32
 gp_in_vm86:
        local_irq_enable();
        handle_vm86_fault((struct kernel_vm86_regs *) regs, error_code);
        return;
+#endif
 
 gp_in_kernel:
        if (fixup_exception(regs))
@@ -690,7 +378,8 @@ mem_parity_error(unsigned char reason, struct pt_regs *regs)
        printk(KERN_EMERG "Dazed and confused, but trying to continue\n");
 
        /* Clear and disable the memory parity error line. */
-       clear_mem_error(reason);
+       reason = (reason & 0xf) | 4;
+       outb(reason, 0x61);
 }
 
 static notrace __kprobes void
@@ -716,7 +405,8 @@ io_check_error(unsigned char reason, struct pt_regs *regs)
 static notrace __kprobes void
 unknown_nmi_error(unsigned char reason, struct pt_regs *regs)
 {
-       if (notify_die(DIE_NMIUNKNOWN, "nmi", regs, reason, 2, SIGINT) == NOTIFY_STOP)
+       if (notify_die(DIE_NMIUNKNOWN, "nmi", regs, reason, 2, SIGINT) ==
+                       NOTIFY_STOP)
                return;
 #ifdef CONFIG_MCA
        /*
@@ -739,41 +429,6 @@ unknown_nmi_error(unsigned char reason, struct pt_regs *regs)
        printk(KERN_EMERG "Dazed and confused, but trying to continue\n");
 }
 
-static DEFINE_SPINLOCK(nmi_print_lock);
-
-void notrace __kprobes die_nmi(char *str, struct pt_regs *regs, int do_panic)
-{
-       if (notify_die(DIE_NMIWATCHDOG, str, regs, 0, 2, SIGINT) == NOTIFY_STOP)
-               return;
-
-       spin_lock(&nmi_print_lock);
-       /*
-       * We are in trouble anyway, lets at least try
-       * to get a message out:
-       */
-       bust_spinlocks(1);
-       printk(KERN_EMERG "%s", str);
-       printk(" on CPU%d, ip %08lx, registers:\n",
-               smp_processor_id(), regs->ip);
-       show_registers(regs);
-       if (do_panic)
-               panic("Non maskable interrupt");
-       console_silent();
-       spin_unlock(&nmi_print_lock);
-       bust_spinlocks(0);
-
-       /*
-        * If we are in kernel we are probably nested up pretty bad
-        * and might aswell get out now while we still can:
-        */
-       if (!user_mode_vm(regs)) {
-               current->thread.trap_no = 2;
-               crash_kexec(regs);
-       }
-
-       do_exit(SIGSEGV);
-}
-
 static notrace __kprobes void default_do_nmi(struct pt_regs *regs)
 {
        unsigned char reason = 0;
@@ -812,22 +467,25 @@ static notrace __kprobes void default_do_nmi(struct pt_regs *regs)
                mem_parity_error(reason, regs);
        if (reason & 0x40)
                io_check_error(reason, regs);
+#ifdef CONFIG_X86_32
        /*
         * Reassert NMI in case it became active meanwhile
         * as it's edge-triggered:
         */
        reassert_nmi();
+#endif
 }
 
-notrace __kprobes void do_nmi(struct pt_regs *regs, long error_code)
+dotraplinkage notrace __kprobes void
+do_nmi(struct pt_regs *regs, long error_code)
 {
-       int cpu;
-
        nmi_enter();
 
-       cpu = smp_processor_id();
-
-       ++nmi_count(cpu);
+#ifdef CONFIG_X86_32
+       { int cpu; cpu = smp_processor_id(); ++nmi_count(cpu); }
+#else
+       add_pda(__nmi_count, 1);
+#endif
 
        if (!ignore_nmis)
                default_do_nmi(regs);
@@ -847,21 +505,44 @@ void restart_nmi(void)
        acpi_nmi_enable();
 }
 
-#ifdef CONFIG_KPROBES
-void __kprobes do_int3(struct pt_regs *regs, long error_code)
+/* May run on IST stack. */
+dotraplinkage void __kprobes do_int3(struct pt_regs *regs, long error_code)
 {
-       trace_hardirqs_fixup();
-
+#ifdef CONFIG_KPROBES
        if (notify_die(DIE_INT3, "int3", regs, error_code, 3, SIGTRAP)
                        == NOTIFY_STOP)
                return;
-       /*
-        * This is an interrupt gate, because kprobes wants interrupts
-        * disabled. Normal trap handlers don't.
-        */
-       restore_interrupts(regs);
+#else
+       if (notify_die(DIE_TRAP, "int3", regs, error_code, 3, SIGTRAP)
+                       == NOTIFY_STOP)
+               return;
+#endif
+
+       preempt_conditional_sti(regs);
+       do_trap(3, SIGTRAP, "int3", regs, error_code, NULL);
+       preempt_conditional_cli(regs);
+}
 
-       do_trap(3, SIGTRAP, "int3", 1, regs, error_code, NULL);
+#ifdef CONFIG_X86_64
+/* Help handler running on IST stack to switch back to user stack
+   for scheduling or signal handling. The actual stack switch is done in
+   entry.S */
+asmlinkage __kprobes struct pt_regs *sync_regs(struct pt_regs *eregs)
+{
+       struct pt_regs *regs = eregs;
+       /* Did already sync */
+       if (eregs == (struct pt_regs *)eregs->sp)
+               ;
+       /* Exception from user space */
+       else if (user_mode(eregs))
+               regs = task_pt_regs(current);
+       /* Exception from kernel and interrupts are enabled. Move to
+          kernel process stack. */
+       else if (eregs->flags & X86_EFLAGS_IF)
+               regs = (struct pt_regs *)(eregs->sp -= sizeof(struct pt_regs));
+       if (eregs != regs)
+               *regs = *eregs;
+       return regs;
 }
 #endif
 
@@ -886,15 +567,15 @@ void __kprobes do_int3(struct pt_regs *regs, long error_code)
  * about restoring all the debug state, and ptrace doesn't have to
  * find every occurrence of the TF bit that could be saved away even
  * by user code)
+ *
+ * May run on IST stack.
  */
-void __kprobes do_debug(struct pt_regs *regs, long error_code)
+dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
 {
        struct task_struct *tsk = current;
-       unsigned int condition;
+       unsigned long condition;
        int si_code;
 
-       trace_hardirqs_fixup();
-
        get_debugreg(condition, 6);
 
        /*
@@ -906,9 +587,9 @@ void __kprobes do_debug(struct pt_regs *regs, long error_code)
        if (notify_die(DIE_DEBUG, "debug", regs, condition, error_code,
                                                SIGTRAP) == NOTIFY_STOP)
                return;
+
        /* It's safe to allow irq's after DR6 has been saved */
-       if (regs->flags & X86_EFLAGS_IF)
-               local_irq_enable();
+       preempt_conditional_sti(regs);
 
        /* Mask out spurious debug traps due to lazy DR7 setting */
        if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) {
@@ -916,8 +597,10 @@ void __kprobes do_debug(struct pt_regs *regs, long error_code)
                        goto clear_dr7;
        }
 
+#ifdef CONFIG_X86_32
        if (regs->flags & X86_VM_MASK)
                goto debug_vm86;
+#endif
 
        /* Save debug status register where ptrace can see it */
        tsk->thread.debugreg6 = condition;
@@ -927,16 +610,11 @@ void __kprobes do_debug(struct pt_regs *regs, long error_code)
         * kernel space (but re-enable TF when returning to user mode).
         */
        if (condition & DR_STEP) {
-               /*
-                * We already checked v86 mode above, so we can
-                * check for kernel mode by just checking the CPL
-                * of CS.
-                */
                if (!user_mode(regs))
                        goto clear_TF_reenable;
        }
 
-       si_code = get_si_code((unsigned long)condition);
+       si_code = get_si_code(condition);
        /* Ok, finally something we can handle */
        send_sigtrap(tsk, regs, error_code, si_code);
 
@@ -946,18 +624,37 @@ void __kprobes do_debug(struct pt_regs *regs, long error_code)
         */
 clear_dr7:
        set_debugreg(0, 7);
+       preempt_conditional_cli(regs);
        return;
 
+#ifdef CONFIG_X86_32
 debug_vm86:
        handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, 1);
+       preempt_conditional_cli(regs);
        return;
+#endif
 
 clear_TF_reenable:
        set_tsk_thread_flag(tsk, TIF_SINGLESTEP);
        regs->flags &= ~X86_EFLAGS_TF;
+       preempt_conditional_cli(regs);
        return;
 }
 
+#ifdef CONFIG_X86_64
+static int kernel_math_error(struct pt_regs *regs, const char *str, int trapnr)
+{
+       if (fixup_exception(regs))
+               return 1;
+
+       notify_die(DIE_GPF, str, regs, 0, trapnr, SIGFPE);
+       /* Illegal floating point operation in the kernel */
+       current->thread.trap_no = trapnr;
+       die(str, regs, 0);
+       return 0;
+}
+#endif
+
 /*
  * Note that we play around with the 'TS' bit in an attempt to get
  * the correct behaviour even in the presence of the asynchronous
@@ -994,7 +691,9 @@ void math_error(void __user *ip)
        swd = get_fpu_swd(task);
        switch (swd & ~cwd & 0x3f) {
        case 0x000: /* No unmasked exception */
+#ifdef CONFIG_X86_32
                return;
+#endif
        default: /* Multiple exceptions */
                break;
        case 0x001: /* Invalid Op */
@@ -1022,9 +721,18 @@ void math_error(void __user *ip)
        force_sig_info(SIGFPE, &info, task);
 }
 
-void do_coprocessor_error(struct pt_regs *regs, long error_code)
+dotraplinkage void do_coprocessor_error(struct pt_regs *regs, long error_code)
 {
+       conditional_sti(regs);
+
+#ifdef CONFIG_X86_32
        ignore_fpu_irq = 1;
+#else
+       if (!user_mode(regs) &&
+           kernel_math_error(regs, "kernel x87 math error", 16))
+               return;
+#endif
+
        math_error((void __user *)regs->ip);
 }
 
@@ -1076,8 +784,12 @@ static void simd_math_error(void __user *ip)
        force_sig_info(SIGFPE, &info, task);
 }
 
-void do_simd_coprocessor_error(struct pt_regs *regs, long error_code)
+dotraplinkage void
+do_simd_coprocessor_error(struct pt_regs *regs, long error_code)
 {
+       conditional_sti(regs);
+
+#ifdef CONFIG_X86_32
        if (cpu_has_xmm) {
                /* Handle SIMD FPU exceptions on PIII+ processors. */
                ignore_fpu_irq = 1;
@@ -1096,16 +808,25 @@ void do_simd_coprocessor_error(struct pt_regs *regs, long error_code)
        current->thread.error_code = error_code;
        die_if_kernel("cache flush denied", regs, error_code);
        force_sig(SIGSEGV, current);
+#else
+       if (!user_mode(regs) &&
+                       kernel_math_error(regs, "kernel simd math error", 19))
+               return;
+       simd_math_error((void __user *)regs->ip);
+#endif
 }
 
-void do_spurious_interrupt_bug(struct pt_regs *regs, long error_code)
+dotraplinkage void
+do_spurious_interrupt_bug(struct pt_regs *regs, long error_code)
 {
+       conditional_sti(regs);
 #if 0
        /* No need to warn about this any longer. */
        printk(KERN_INFO "Ignoring P6 Local APIC Spurious Interrupt Bug...\n");
 #endif
 }
 
+#ifdef CONFIG_X86_32
 unsigned long patch_espfix_desc(unsigned long uesp, unsigned long kesp)
 {
        struct desc_struct *gdt = get_cpu_gdt_table(smp_processor_id());
@@ -1124,6 +845,15 @@ unsigned long patch_espfix_desc(unsigned long uesp, unsigned long kesp)
 
        return new_kesp;
 }
+#else
+asmlinkage void __attribute__((weak)) smp_thermal_interrupt(void)
+{
+}
+
+asmlinkage void __attribute__((weak)) mce_threshold_interrupt(void)
+{
+}
+#endif
 
 /*
  * 'math_state_restore()' saves the current math information in the
@@ -1156,14 +886,24 @@ asmlinkage void math_state_restore(void)
        }
 
        clts();                         /* Allow maths ops (or we recurse) */
+#ifdef CONFIG_X86_32
        restore_fpu(tsk);
+#else
+       /*
+        * Paranoid restore. send a SIGSEGV if we fail to restore the state.
+        */
+       if (unlikely(restore_fpu_checking(tsk))) {
+               stts();
+               force_sig(SIGSEGV, tsk);
+               return;
+       }
+#endif
        thread->status |= TS_USEDFPU;   /* So we fnsave on switch_to() */
        tsk->fpu_counter++;
 }
 EXPORT_SYMBOL_GPL(math_state_restore);
 
 #ifndef CONFIG_MATH_EMULATION
-
 asmlinkage void math_emulate(long arg)
 {
        printk(KERN_EMERG
@@ -1172,12 +912,54 @@ asmlinkage void math_emulate(long arg)
        force_sig(SIGFPE, current);
        schedule();
 }
-
 #endif /* CONFIG_MATH_EMULATION */
 
+dotraplinkage void __kprobes
+do_device_not_available(struct pt_regs *regs, long error)
+{
+#ifdef CONFIG_X86_32
+       if (read_cr0() & X86_CR0_EM) {
+               conditional_sti(regs);
+               math_emulate(0);
+       } else {
+               math_state_restore(); /* interrupts still off */
+               conditional_sti(regs);
+       }
+#else
+       math_state_restore();
+#endif
+}
+
+#ifdef CONFIG_X86_32
+#ifdef CONFIG_X86_MCE
+dotraplinkage void __kprobes do_machine_check(struct pt_regs *regs, long error)
+{
+       conditional_sti(regs);
+       machine_check_vector(regs, error);
+}
+#endif
+
+dotraplinkage void do_iret_error(struct pt_regs *regs, long error_code)
+{
+       siginfo_t info;
+       local_irq_enable();
+
+       info.si_signo = SIGILL;
+       info.si_errno = 0;
+       info.si_code = ILL_BADSTK;
+       info.si_addr = 0;
+       if (notify_die(DIE_TRAP, "iret exception",
+                       regs, error_code, 32, SIGILL) == NOTIFY_STOP)
+               return;
+       do_trap(32, SIGILL, "iret exception", regs, error_code, &info);
+}
+#endif
+
 void __init trap_init(void)
 {
+#ifdef CONFIG_X86_32
        int i;
+#endif
 
 #ifdef CONFIG_EISA
        void __iomem *p = early_ioremap(0x0FFFD9, 4);
@@ -1187,29 +969,40 @@ void __init trap_init(void)
        early_iounmap(p, 4);
 #endif
 
-       set_trap_gate(0, &divide_error);
-       set_intr_gate(1, &debug);
-       set_intr_gate(2, &nmi);
-       set_system_intr_gate(3, &int3); /* int3 can be called from all */
-       set_system_gate(4, &overflow); /* int4 can be called from all */
-       set_trap_gate(5, &bounds);
-       set_trap_gate(6, &invalid_op);
-       set_trap_gate(7, &device_not_available);
+       set_intr_gate(0, &divide_error);
+       set_intr_gate_ist(1, &debug, DEBUG_STACK);
+       set_intr_gate_ist(2, &nmi, NMI_STACK);
+       /* int3 can be called from all */
+       set_system_intr_gate_ist(3, &int3, DEBUG_STACK);
+       /* int4 can be called from all */
+       set_system_intr_gate(4, &overflow);
+       set_intr_gate(5, &bounds);
+       set_intr_gate(6, &invalid_op);
+       set_intr_gate(7, &device_not_available);
+#ifdef CONFIG_X86_32
        set_task_gate(8, GDT_ENTRY_DOUBLEFAULT_TSS);
-       set_trap_gate(9, &coprocessor_segment_overrun);
-       set_trap_gate(10, &invalid_TSS);
-       set_trap_gate(11, &segment_not_present);
-       set_trap_gate(12, &stack_segment);
-       set_trap_gate(13, &general_protection);
+#else
+       set_intr_gate_ist(8, &double_fault, DOUBLEFAULT_STACK);
+#endif
+       set_intr_gate(9, &coprocessor_segment_overrun);
+       set_intr_gate(10, &invalid_TSS);
+       set_intr_gate(11, &segment_not_present);
+       set_intr_gate_ist(12, &stack_segment, STACKFAULT_STACK);
+       set_intr_gate(13, &general_protection);
        set_intr_gate(14, &page_fault);
-       set_trap_gate(15, &spurious_interrupt_bug);
-       set_trap_gate(16, &coprocessor_error);
-       set_trap_gate(17, &alignment_check);
+       set_intr_gate(15, &spurious_interrupt_bug);
+       set_intr_gate(16, &coprocessor_error);
+       set_intr_gate(17, &alignment_check);
 #ifdef CONFIG_X86_MCE
-       set_trap_gate(18, &machine_check);
+       set_intr_gate_ist(18, &machine_check, MCE_STACK);
 #endif
-       set_trap_gate(19, &simd_coprocessor_error);
+       set_intr_gate(19, &simd_coprocessor_error);
 
+#ifdef CONFIG_IA32_EMULATION
+       set_system_intr_gate(IA32_SYSCALL_VECTOR, ia32_syscall);
+#endif
+
+#ifdef CONFIG_X86_32
        if (cpu_has_fxsr) {
                printk(KERN_INFO "Enabling fast FPU save and restore... ");
                set_in_cr4(X86_CR4_OSFXSR);
@@ -1222,36 +1015,20 @@ void __init trap_init(void)
                printk("done.\n");
        }
 
-       set_system_gate(SYSCALL_VECTOR, &system_call);
+       set_system_trap_gate(SYSCALL_VECTOR, &system_call);
 
        /* Reserve all the builtin and the syscall vector: */
        for (i = 0; i < FIRST_EXTERNAL_VECTOR; i++)
                set_bit(i, used_vectors);
 
        set_bit(SYSCALL_VECTOR, used_vectors);
-
+#endif
        /*
         * Should be a barrier for any external CPU state:
         */
        cpu_init();
 
+#ifdef CONFIG_X86_32
        trap_init_hook();
+#endif
 }
-
-static int __init kstack_setup(char *s)
-{
-       kstack_depth_to_print = simple_strtoul(s, NULL, 0);
-
-       return 1;
-}
-__setup("kstack=", kstack_setup);
-
-static int __init code_bytes_setup(char *s)
-{
-       code_bytes = simple_strtoul(s, NULL, 0);
-       if (code_bytes > 8192)
-               code_bytes = 8192;
-
-       return 1;
-}
-__setup("code_bytes=", code_bytes_setup);
diff --git a/arch/x86/kernel/traps_64.c b/arch/x86/kernel/traps_64.c
deleted file mode 100644 (file)
index 9c0ac0c..0000000
+++ /dev/null
@@ -1,1214 +0,0 @@
-/*
- *  Copyright (C) 1991, 1992  Linus Torvalds
- *  Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs
- *
- *  Pentium III FXSR, SSE support
- *     Gareth Hughes <gareth@valinux.com>, May 2000
- */
-
-/*
- * 'Traps.c' handles hardware traps and faults after we have saved some
- * state in 'entry.S'.
- */
-#include <linux/moduleparam.h>
-#include <linux/interrupt.h>
-#include <linux/kallsyms.h>
-#include <linux/spinlock.h>
-#include <linux/kprobes.h>
-#include <linux/uaccess.h>
-#include <linux/utsname.h>
-#include <linux/kdebug.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/ptrace.h>
-#include <linux/string.h>
-#include <linux/unwind.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/kexec.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/init.h>
-#include <linux/bug.h>
-#include <linux/nmi.h>
-#include <linux/mm.h>
-#include <linux/smp.h>
-#include <linux/io.h>
-
-#if defined(CONFIG_EDAC)
-#include <linux/edac.h>
-#endif
-
-#include <asm/stacktrace.h>
-#include <asm/processor.h>
-#include <asm/debugreg.h>
-#include <asm/atomic.h>
-#include <asm/system.h>
-#include <asm/unwind.h>
-#include <asm/desc.h>
-#include <asm/i387.h>
-#include <asm/pgalloc.h>
-#include <asm/proto.h>
-#include <asm/pda.h>
-#include <asm/traps.h>
-
-#include <mach_traps.h>
-
-int panic_on_unrecovered_nmi;
-int kstack_depth_to_print = 12;
-static unsigned int code_bytes = 64;
-static int ignore_nmis;
-static int die_counter;
-
-static inline void conditional_sti(struct pt_regs *regs)
-{
-       if (regs->flags & X86_EFLAGS_IF)
-               local_irq_enable();
-}
-
-static inline void preempt_conditional_sti(struct pt_regs *regs)
-{
-       inc_preempt_count();
-       if (regs->flags & X86_EFLAGS_IF)
-               local_irq_enable();
-}
-
-static inline void preempt_conditional_cli(struct pt_regs *regs)
-{
-       if (regs->flags & X86_EFLAGS_IF)
-               local_irq_disable();
-       /* Make sure to not schedule here because we could be running
-          on an exception stack. */
-       dec_preempt_count();
-}
-
-void printk_address(unsigned long address, int reliable)
-{
-       printk(" [<%016lx>] %s%pS\n",
-                       address, reliable ?     "" : "? ", (void *) address);
-}
-
-static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack,
-                                       unsigned *usedp, char **idp)
-{
-       static char ids[][8] = {
-               [DEBUG_STACK - 1] = "#DB",
-               [NMI_STACK - 1] = "NMI",
-               [DOUBLEFAULT_STACK - 1] = "#DF",
-               [STACKFAULT_STACK - 1] = "#SS",
-               [MCE_STACK - 1] = "#MC",
-#if DEBUG_STKSZ > EXCEPTION_STKSZ
-               [N_EXCEPTION_STACKS ...
-                       N_EXCEPTION_STACKS + DEBUG_STKSZ / EXCEPTION_STKSZ - 2] = "#DB[?]"
-#endif
-       };
-       unsigned k;
-
-       /*
-        * Iterate over all exception stacks, and figure out whether
-        * 'stack' is in one of them:
-        */
-       for (k = 0; k < N_EXCEPTION_STACKS; k++) {
-               unsigned long end = per_cpu(orig_ist, cpu).ist[k];
-               /*
-                * Is 'stack' above this exception frame's end?
-                * If yes then skip to the next frame.
-                */
-               if (stack >= end)
-                       continue;
-               /*
-                * Is 'stack' above this exception frame's start address?
-                * If yes then we found the right frame.
-                */
-               if (stack >= end - EXCEPTION_STKSZ) {
-                       /*
-                        * Make sure we only iterate through an exception
-                        * stack once. If it comes up for the second time
-                        * then there's something wrong going on - just
-                        * break out and return NULL:
-                        */
-                       if (*usedp & (1U << k))
-                               break;
-                       *usedp |= 1U << k;
-                       *idp = ids[k];
-                       return (unsigned long *)end;
-               }
-               /*
-                * If this is a debug stack, and if it has a larger size than
-                * the usual exception stacks, then 'stack' might still
-                * be within the lower portion of the debug stack:
-                */
-#if DEBUG_STKSZ > EXCEPTION_STKSZ
-               if (k == DEBUG_STACK - 1 && stack >= end - DEBUG_STKSZ) {
-                       unsigned j = N_EXCEPTION_STACKS - 1;
-
-                       /*
-                        * Black magic. A large debug stack is composed of
-                        * multiple exception stack entries, which we
-                        * iterate through now. Dont look:
-                        */
-                       do {
-                               ++j;
-                               end -= EXCEPTION_STKSZ;
-                               ids[j][4] = '1' + (j - N_EXCEPTION_STACKS);
-                       } while (stack < end - EXCEPTION_STKSZ);
-                       if (*usedp & (1U << j))
-                               break;
-                       *usedp |= 1U << j;
-                       *idp = ids[j];
-                       return (unsigned long *)end;
-               }
-#endif
-       }
-       return NULL;
-}
-
-/*
- * x86-64 can have up to three kernel stacks:
- * process stack
- * interrupt stack
- * severe exception (double fault, nmi, stack fault, debug, mce) hardware stack
- */
-
-static inline int valid_stack_ptr(struct thread_info *tinfo,
-                       void *p, unsigned int size, void *end)
-{
-       void *t = tinfo;
-       if (end) {
-               if (p < end && p >= (end-THREAD_SIZE))
-                       return 1;
-               else
-                       return 0;
-       }
-       return p > t && p < t + THREAD_SIZE - size;
-}
-
-/* The form of the top of the frame on the stack */
-struct stack_frame {
-       struct stack_frame *next_frame;
-       unsigned long return_address;
-};
-
-static inline unsigned long
-print_context_stack(struct thread_info *tinfo,
-               unsigned long *stack, unsigned long bp,
-               const struct stacktrace_ops *ops, void *data,
-               unsigned long *end)
-{
-       struct stack_frame *frame = (struct stack_frame *)bp;
-
-       while (valid_stack_ptr(tinfo, stack, sizeof(*stack), end)) {
-               unsigned long addr;
-
-               addr = *stack;
-               if (__kernel_text_address(addr)) {
-                       if ((unsigned long) stack == bp + 8) {
-                               ops->address(data, addr, 1);
-                               frame = frame->next_frame;
-                               bp = (unsigned long) frame;
-                       } else {
-                               ops->address(data, addr, bp == 0);
-                       }
-               }
-               stack++;
-       }
-       return bp;
-}
-
-void dump_trace(struct task_struct *task, struct pt_regs *regs,
-               unsigned long *stack, unsigned long bp,
-               const struct stacktrace_ops *ops, void *data)
-{
-       const unsigned cpu = get_cpu();
-       unsigned long *irqstack_end = (unsigned long *)cpu_pda(cpu)->irqstackptr;
-       unsigned used = 0;
-       struct thread_info *tinfo;
-
-       if (!task)
-               task = current;
-
-       if (!stack) {
-               unsigned long dummy;
-               stack = &dummy;
-               if (task && task != current)
-                       stack = (unsigned long *)task->thread.sp;
-       }
-
-#ifdef CONFIG_FRAME_POINTER
-       if (!bp) {
-               if (task == current) {
-                       /* Grab bp right from our regs */
-                       asm("movq %%rbp, %0" : "=r" (bp) : );
-               } else {
-                       /* bp is the last reg pushed by switch_to */
-                       bp = *(unsigned long *) task->thread.sp;
-               }
-       }
-#endif
-
-       /*
-        * Print function call entries in all stacks, starting at the
-        * current stack address. If the stacks consist of nested
-        * exceptions
-        */
-       tinfo = task_thread_info(task);
-       for (;;) {
-               char *id;
-               unsigned long *estack_end;
-               estack_end = in_exception_stack(cpu, (unsigned long)stack,
-                                               &used, &id);
-
-               if (estack_end) {
-                       if (ops->stack(data, id) < 0)
-                               break;
-
-                       bp = print_context_stack(tinfo, stack, bp, ops,
-                                                       data, estack_end);
-                       ops->stack(data, "<EOE>");
-                       /*
-                        * We link to the next stack via the
-                        * second-to-last pointer (index -2 to end) in the
-                        * exception stack:
-                        */
-                       stack = (unsigned long *) estack_end[-2];
-                       continue;
-               }
-               if (irqstack_end) {
-                       unsigned long *irqstack;
-                       irqstack = irqstack_end -
-                               (IRQSTACKSIZE - 64) / sizeof(*irqstack);
-
-                       if (stack >= irqstack && stack < irqstack_end) {
-                               if (ops->stack(data, "IRQ") < 0)
-                                       break;
-                               bp = print_context_stack(tinfo, stack, bp,
-                                               ops, data, irqstack_end);
-                               /*
-                                * We link to the next stack (which would be
-                                * the process stack normally) the last
-                                * pointer (index -1 to end) in the IRQ stack:
-                                */
-                               stack = (unsigned long *) (irqstack_end[-1]);
-                               irqstack_end = NULL;
-                               ops->stack(data, "EOI");
-                               continue;
-                       }
-               }
-               break;
-       }
-
-       /*
-        * This handles the process stack:
-        */
-       bp = print_context_stack(tinfo, stack, bp, ops, data, NULL);
-       put_cpu();
-}
-EXPORT_SYMBOL(dump_trace);
-
-static void
-print_trace_warning_symbol(void *data, char *msg, unsigned long symbol)
-{
-       print_symbol(msg, symbol);
-       printk("\n");
-}
-
-static void print_trace_warning(void *data, char *msg)
-{
-       printk("%s\n", msg);
-}
-
-static int print_trace_stack(void *data, char *name)
-{
-       printk(" <%s> ", name);
-       return 0;
-}
-
-static void print_trace_address(void *data, unsigned long addr, int reliable)
-{
-       touch_nmi_watchdog();
-       printk_address(addr, reliable);
-}
-
-static const struct stacktrace_ops print_trace_ops = {
-       .warning = print_trace_warning,
-       .warning_symbol = print_trace_warning_symbol,
-       .stack = print_trace_stack,
-       .address = print_trace_address,
-};
-
-static void
-show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs,
-               unsigned long *stack, unsigned long bp, char *log_lvl)
-{
-       printk("Call Trace:\n");
-       dump_trace(task, regs, stack, bp, &print_trace_ops, log_lvl);
-}
-
-void show_trace(struct task_struct *task, struct pt_regs *regs,
-               unsigned long *stack, unsigned long bp)
-{
-       show_trace_log_lvl(task, regs, stack, bp, "");
-}
-
-static void
-show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
-               unsigned long *sp, unsigned long bp, char *log_lvl)
-{
-       unsigned long *stack;
-       int i;
-       const int cpu = smp_processor_id();
-       unsigned long *irqstack_end =
-               (unsigned long *) (cpu_pda(cpu)->irqstackptr);
-       unsigned long *irqstack =
-               (unsigned long *) (cpu_pda(cpu)->irqstackptr - IRQSTACKSIZE);
-
-       /*
-        * debugging aid: "show_stack(NULL, NULL);" prints the
-        * back trace for this cpu.
-        */
-
-       if (sp == NULL) {
-               if (task)
-                       sp = (unsigned long *)task->thread.sp;
-               else
-                       sp = (unsigned long *)&sp;
-       }
-
-       stack = sp;
-       for (i = 0; i < kstack_depth_to_print; i++) {
-               if (stack >= irqstack && stack <= irqstack_end) {
-                       if (stack == irqstack_end) {
-                               stack = (unsigned long *) (irqstack_end[-1]);
-                               printk(" <EOI> ");
-                       }
-               } else {
-               if (((long) stack & (THREAD_SIZE-1)) == 0)
-                       break;
-               }
-               if (i && ((i % 4) == 0))
-                       printk("\n");
-               printk(" %016lx", *stack++);
-               touch_nmi_watchdog();
-       }
-       printk("\n");
-       show_trace_log_lvl(task, regs, sp, bp, log_lvl);
-}
-
-void show_stack(struct task_struct *task, unsigned long *sp)
-{
-       show_stack_log_lvl(task, NULL, sp, 0, "");
-}
-
-/*
- * The architecture-independent dump_stack generator
- */
-void dump_stack(void)
-{
-       unsigned long bp = 0;
-       unsigned long stack;
-
-#ifdef CONFIG_FRAME_POINTER
-       if (!bp)
-               asm("movq %%rbp, %0" : "=r" (bp) : );
-#endif
-
-       printk("Pid: %d, comm: %.20s %s %s %.*s\n",
-               current->pid, current->comm, print_tainted(),
-               init_utsname()->release,
-               (int)strcspn(init_utsname()->version, " "),
-               init_utsname()->version);
-       show_trace(NULL, NULL, &stack, bp);
-}
-EXPORT_SYMBOL(dump_stack);
-
-void show_registers(struct pt_regs *regs)
-{
-       int i;
-       unsigned long sp;
-       const int cpu = smp_processor_id();
-       struct task_struct *cur = cpu_pda(cpu)->pcurrent;
-
-       sp = regs->sp;
-       printk("CPU %d ", cpu);
-       __show_regs(regs);
-       printk("Process %s (pid: %d, threadinfo %p, task %p)\n",
-               cur->comm, cur->pid, task_thread_info(cur), cur);
-
-       /*
-        * When in-kernel, we also print out the stack and code at the
-        * time of the fault..
-        */
-       if (!user_mode(regs)) {
-               unsigned int code_prologue = code_bytes * 43 / 64;
-               unsigned int code_len = code_bytes;
-               unsigned char c;
-               u8 *ip;
-
-               printk("Stack: ");
-               show_stack_log_lvl(NULL, regs, (unsigned long *)sp,
-                               regs->bp, "");
-
-               printk(KERN_EMERG "Code: ");
-
-               ip = (u8 *)regs->ip - code_prologue;
-               if (ip < (u8 *)PAGE_OFFSET || probe_kernel_address(ip, c)) {
-                       /* try starting at RIP */
-                       ip = (u8 *)regs->ip;
-                       code_len = code_len - code_prologue + 1;
-               }
-               for (i = 0; i < code_len; i++, ip++) {
-                       if (ip < (u8 *)PAGE_OFFSET ||
-                                       probe_kernel_address(ip, c)) {
-                               printk(" Bad RIP value.");
-                               break;
-                       }
-                       if (ip == (u8 *)regs->ip)
-                               printk("<%02x> ", c);
-                       else
-                               printk("%02x ", c);
-               }
-       }
-       printk("\n");
-}
-
-int is_valid_bugaddr(unsigned long ip)
-{
-       unsigned short ud2;
-
-       if (__copy_from_user(&ud2, (const void __user *) ip, sizeof(ud2)))
-               return 0;
-
-       return ud2 == 0x0b0f;
-}
-
-static raw_spinlock_t die_lock = __RAW_SPIN_LOCK_UNLOCKED;
-static int die_owner = -1;
-static unsigned int die_nest_count;
-
-unsigned __kprobes long oops_begin(void)
-{
-       int cpu;
-       unsigned long flags;
-
-       oops_enter();
-
-       /* racy, but better than risking deadlock. */
-       raw_local_irq_save(flags);
-       cpu = smp_processor_id();
-       if (!__raw_spin_trylock(&die_lock)) {
-               if (cpu == die_owner)
-                       /* nested oops. should stop eventually */;
-               else
-                       __raw_spin_lock(&die_lock);
-       }
-       die_nest_count++;
-       die_owner = cpu;
-       console_verbose();
-       bust_spinlocks(1);
-       return flags;
-}
-
-void __kprobes oops_end(unsigned long flags, struct pt_regs *regs, int signr)
-{
-       die_owner = -1;
-       bust_spinlocks(0);
-       die_nest_count--;
-       if (!die_nest_count)
-               /* Nest count reaches zero, release the lock. */
-               __raw_spin_unlock(&die_lock);
-       raw_local_irq_restore(flags);
-       if (!regs) {
-               oops_exit();
-               return;
-       }
-       if (panic_on_oops)
-               panic("Fatal exception");
-       oops_exit();
-       do_exit(signr);
-}
-
-int __kprobes __die(const char *str, struct pt_regs *regs, long err)
-{
-       printk(KERN_EMERG "%s: %04lx [%u] ", str, err & 0xffff, ++die_counter);
-#ifdef CONFIG_PREEMPT
-       printk("PREEMPT ");
-#endif
-#ifdef CONFIG_SMP
-       printk("SMP ");
-#endif
-#ifdef CONFIG_DEBUG_PAGEALLOC
-       printk("DEBUG_PAGEALLOC");
-#endif
-       printk("\n");
-       if (notify_die(DIE_OOPS, str, regs, err,
-                       current->thread.trap_no, SIGSEGV) == NOTIFY_STOP)
-               return 1;
-
-       show_registers(regs);
-       add_taint(TAINT_DIE);
-       /* Executive summary in case the oops scrolled away */
-       printk(KERN_ALERT "RIP ");
-       printk_address(regs->ip, 1);
-       printk(" RSP <%016lx>\n", regs->sp);
-       if (kexec_should_crash(current))
-               crash_kexec(regs);
-       return 0;
-}
-
-void die(const char *str, struct pt_regs *regs, long err)
-{
-       unsigned long flags = oops_begin();
-
-       if (!user_mode(regs))
-               report_bug(regs->ip, regs);
-
-       if (__die(str, regs, err))
-               regs = NULL;
-       oops_end(flags, regs, SIGSEGV);
-}
-
-notrace __kprobes void
-die_nmi(char *str, struct pt_regs *regs, int do_panic)
-{
-       unsigned long flags;
-
-       if (notify_die(DIE_NMIWATCHDOG, str, regs, 0, 2, SIGINT) == NOTIFY_STOP)
-               return;
-
-       flags = oops_begin();
-       /*
-        * We are in trouble anyway, lets at least try
-        * to get a message out.
-        */
-       printk(KERN_EMERG "%s", str);
-       printk(" on CPU%d, ip %08lx, registers:\n",
-               smp_processor_id(), regs->ip);
-       show_registers(regs);
-       if (kexec_should_crash(current))
-               crash_kexec(regs);
-       if (do_panic || panic_on_oops)
-               panic("Non maskable interrupt");
-       oops_end(flags, NULL, SIGBUS);
-       nmi_exit();
-       local_irq_enable();
-       do_exit(SIGBUS);
-}
-
-static void __kprobes
-do_trap(int trapnr, int signr, char *str, struct pt_regs *regs,
-       long error_code, siginfo_t *info)
-{
-       struct task_struct *tsk = current;
-
-       if (!user_mode(regs))
-               goto kernel_trap;
-
-       /*
-        * We want error_code and trap_no set for userspace faults and
-        * kernelspace faults which result in die(), but not
-        * kernelspace faults which are fixed up.  die() gives the
-        * process no chance to handle the signal and notice the
-        * kernel fault information, so that won't result in polluting
-        * the information about previously queued, but not yet
-        * delivered, faults.  See also do_general_protection below.
-        */
-       tsk->thread.error_code = error_code;
-       tsk->thread.trap_no = trapnr;
-
-       if (show_unhandled_signals && unhandled_signal(tsk, signr) &&
-           printk_ratelimit()) {
-               printk(KERN_INFO
-                      "%s[%d] trap %s ip:%lx sp:%lx error:%lx",
-                      tsk->comm, tsk->pid, str,
-                      regs->ip, regs->sp, error_code);
-               print_vma_addr(" in ", regs->ip);
-               printk("\n");
-       }
-
-       if (info)
-               force_sig_info(signr, info, tsk);
-       else
-               force_sig(signr, tsk);
-       return;
-
-kernel_trap:
-       if (!fixup_exception(regs)) {
-               tsk->thread.error_code = error_code;
-               tsk->thread.trap_no = trapnr;
-               die(str, regs, error_code);
-       }
-       return;
-}
-
-#define DO_ERROR(trapnr, signr, str, name) \
-asmlinkage void do_##name(struct pt_regs *regs, long error_code)       \
-{                                                                      \
-       if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr)  \
-                                                       == NOTIFY_STOP) \
-               return;                                                 \
-       conditional_sti(regs);                                          \
-       do_trap(trapnr, signr, str, regs, error_code, NULL);            \
-}
-
-#define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr)                \
-asmlinkage void do_##name(struct pt_regs *regs, long error_code)       \
-{                                                                      \
-       siginfo_t info;                                                 \
-       info.si_signo = signr;                                          \
-       info.si_errno = 0;                                              \
-       info.si_code = sicode;                                          \
-       info.si_addr = (void __user *)siaddr;                           \
-       trace_hardirqs_fixup();                                         \
-       if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr)  \
-                                                       == NOTIFY_STOP) \
-               return;                                                 \
-       conditional_sti(regs);                                          \
-       do_trap(trapnr, signr, str, regs, error_code, &info);           \
-}
-
-DO_ERROR_INFO(0, SIGFPE, "divide error", divide_error, FPE_INTDIV, regs->ip)
-DO_ERROR(4, SIGSEGV, "overflow", overflow)
-DO_ERROR(5, SIGSEGV, "bounds", bounds)
-DO_ERROR_INFO(6, SIGILL, "invalid opcode", invalid_op, ILL_ILLOPN, regs->ip)
-DO_ERROR(9, SIGFPE, "coprocessor segment overrun", coprocessor_segment_overrun)
-DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS)
-DO_ERROR(11, SIGBUS, "segment not present", segment_not_present)
-DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0)
-
-/* Runs on IST stack */
-asmlinkage void do_stack_segment(struct pt_regs *regs, long error_code)
-{
-       if (notify_die(DIE_TRAP, "stack segment", regs, error_code,
-                       12, SIGBUS) == NOTIFY_STOP)
-               return;
-       preempt_conditional_sti(regs);
-       do_trap(12, SIGBUS, "stack segment", regs, error_code, NULL);
-       preempt_conditional_cli(regs);
-}
-
-asmlinkage void do_double_fault(struct pt_regs *regs, long error_code)
-{
-       static const char str[] = "double fault";
-       struct task_struct *tsk = current;
-
-       /* Return not checked because double check cannot be ignored */
-       notify_die(DIE_TRAP, str, regs, error_code, 8, SIGSEGV);
-
-       tsk->thread.error_code = error_code;
-       tsk->thread.trap_no = 8;
-
-       /* This is always a kernel trap and never fixable (and thus must
-          never return). */
-       for (;;)
-               die(str, regs, error_code);
-}
-
-asmlinkage void __kprobes
-do_general_protection(struct pt_regs *regs, long error_code)
-{
-       struct task_struct *tsk;
-
-       conditional_sti(regs);
-
-       tsk = current;
-       if (!user_mode(regs))
-               goto gp_in_kernel;
-
-       tsk->thread.error_code = error_code;
-       tsk->thread.trap_no = 13;
-
-       if (show_unhandled_signals && unhandled_signal(tsk, SIGSEGV) &&
-                       printk_ratelimit()) {
-               printk(KERN_INFO
-                       "%s[%d] general protection ip:%lx sp:%lx error:%lx",
-                       tsk->comm, tsk->pid,
-                       regs->ip, regs->sp, error_code);
-               print_vma_addr(" in ", regs->ip);
-               printk("\n");
-       }
-
-       force_sig(SIGSEGV, tsk);
-       return;
-
-gp_in_kernel:
-       if (fixup_exception(regs))
-               return;
-
-       tsk->thread.error_code = error_code;
-       tsk->thread.trap_no = 13;
-       if (notify_die(DIE_GPF, "general protection fault", regs,
-                               error_code, 13, SIGSEGV) == NOTIFY_STOP)
-               return;
-       die("general protection fault", regs, error_code);
-}
-
-static notrace __kprobes void
-mem_parity_error(unsigned char reason, struct pt_regs *regs)
-{
-       printk(KERN_EMERG "Uhhuh. NMI received for unknown reason %02x.\n",
-               reason);
-       printk(KERN_EMERG "You have some hardware problem, likely on the PCI bus.\n");
-
-#if defined(CONFIG_EDAC)
-       if (edac_handler_set()) {
-               edac_atomic_assert_error();
-               return;
-       }
-#endif
-
-       if (panic_on_unrecovered_nmi)
-               panic("NMI: Not continuing");
-
-       printk(KERN_EMERG "Dazed and confused, but trying to continue\n");
-
-       /* Clear and disable the memory parity error line. */
-       reason = (reason & 0xf) | 4;
-       outb(reason, 0x61);
-}
-
-static notrace __kprobes void
-io_check_error(unsigned char reason, struct pt_regs *regs)
-{
-       printk("NMI: IOCK error (debug interrupt?)\n");
-       show_registers(regs);
-
-       /* Re-enable the IOCK line, wait for a few seconds */
-       reason = (reason & 0xf) | 8;
-       outb(reason, 0x61);
-       mdelay(2000);
-       reason &= ~8;
-       outb(reason, 0x61);
-}
-
-static notrace __kprobes void
-unknown_nmi_error(unsigned char reason, struct pt_regs *regs)
-{
-       if (notify_die(DIE_NMIUNKNOWN, "nmi", regs, reason, 2, SIGINT) ==
-                       NOTIFY_STOP)
-               return;
-       printk(KERN_EMERG "Uhhuh. NMI received for unknown reason %02x.\n",
-               reason);
-       printk(KERN_EMERG "Do you have a strange power saving mode enabled?\n");
-
-       if (panic_on_unrecovered_nmi)
-               panic("NMI: Not continuing");
-
-       printk(KERN_EMERG "Dazed and confused, but trying to continue\n");
-}
-
-/* Runs on IST stack. This code must keep interrupts off all the time.
-   Nested NMIs are prevented by the CPU. */
-asmlinkage notrace __kprobes void default_do_nmi(struct pt_regs *regs)
-{
-       unsigned char reason = 0;
-       int cpu;
-
-       cpu = smp_processor_id();
-
-       /* Only the BSP gets external NMIs from the system. */
-       if (!cpu)
-               reason = get_nmi_reason();
-
-       if (!(reason & 0xc0)) {
-               if (notify_die(DIE_NMI_IPI, "nmi_ipi", regs, reason, 2, SIGINT)
-                                                               == NOTIFY_STOP)
-                       return;
-               /*
-                * Ok, so this is none of the documented NMI sources,
-                * so it must be the NMI watchdog.
-                */
-               if (nmi_watchdog_tick(regs, reason))
-                       return;
-               if (!do_nmi_callback(regs, cpu))
-                       unknown_nmi_error(reason, regs);
-
-               return;
-       }
-       if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) == NOTIFY_STOP)
-               return;
-
-       /* AK: following checks seem to be broken on modern chipsets. FIXME */
-       if (reason & 0x80)
-               mem_parity_error(reason, regs);
-       if (reason & 0x40)
-               io_check_error(reason, regs);
-}
-
-asmlinkage notrace __kprobes void
-do_nmi(struct pt_regs *regs, long error_code)
-{
-       nmi_enter();
-
-       add_pda(__nmi_count, 1);
-
-       if (!ignore_nmis)
-               default_do_nmi(regs);
-
-       nmi_exit();
-}
-
-void stop_nmi(void)
-{
-       acpi_nmi_disable();
-       ignore_nmis++;
-}
-
-void restart_nmi(void)
-{
-       ignore_nmis--;
-       acpi_nmi_enable();
-}
-
-/* runs on IST stack. */
-asmlinkage void __kprobes do_int3(struct pt_regs *regs, long error_code)
-{
-       trace_hardirqs_fixup();
-
-       if (notify_die(DIE_INT3, "int3", regs, error_code, 3, SIGTRAP)
-                       == NOTIFY_STOP)
-               return;
-
-       preempt_conditional_sti(regs);
-       do_trap(3, SIGTRAP, "int3", regs, error_code, NULL);
-       preempt_conditional_cli(regs);
-}
-
-/* Help handler running on IST stack to switch back to user stack
-   for scheduling or signal handling. The actual stack switch is done in
-   entry.S */
-asmlinkage __kprobes struct pt_regs *sync_regs(struct pt_regs *eregs)
-{
-       struct pt_regs *regs = eregs;
-       /* Did already sync */
-       if (eregs == (struct pt_regs *)eregs->sp)
-               ;
-       /* Exception from user space */
-       else if (user_mode(eregs))
-               regs = task_pt_regs(current);
-       /* Exception from kernel and interrupts are enabled. Move to
-          kernel process stack. */
-       else if (eregs->flags & X86_EFLAGS_IF)
-               regs = (struct pt_regs *)(eregs->sp -= sizeof(struct pt_regs));
-       if (eregs != regs)
-               *regs = *eregs;
-       return regs;
-}
-
-/* runs on IST stack. */
-asmlinkage void __kprobes do_debug(struct pt_regs *regs,
-                                  unsigned long error_code)
-{
-       struct task_struct *tsk = current;
-       unsigned long condition;
-       siginfo_t info;
-
-       trace_hardirqs_fixup();
-
-       get_debugreg(condition, 6);
-
-       /*
-        * The processor cleared BTF, so don't mark that we need it set.
-        */
-       clear_tsk_thread_flag(tsk, TIF_DEBUGCTLMSR);
-       tsk->thread.debugctlmsr = 0;
-
-       if (notify_die(DIE_DEBUG, "debug", regs, condition, error_code,
-                                               SIGTRAP) == NOTIFY_STOP)
-               return;
-
-       preempt_conditional_sti(regs);
-
-       /* Mask out spurious debug traps due to lazy DR7 setting */
-       if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) {
-               if (!tsk->thread.debugreg7)
-                       goto clear_dr7;
-       }
-
-       tsk->thread.debugreg6 = condition;
-
-       /*
-        * Single-stepping through TF: make sure we ignore any events in
-        * kernel space (but re-enable TF when returning to user mode).
-        */
-       if (condition & DR_STEP) {
-               if (!user_mode(regs))
-                       goto clear_TF_reenable;
-       }
-
-       /* Ok, finally something we can handle */
-       tsk->thread.trap_no = 1;
-       tsk->thread.error_code = error_code;
-       info.si_signo = SIGTRAP;
-       info.si_errno = 0;
-       info.si_code = get_si_code(condition);
-       info.si_addr = user_mode(regs) ? (void __user *)regs->ip : NULL;
-       force_sig_info(SIGTRAP, &info, tsk);
-
-clear_dr7:
-       set_debugreg(0, 7);
-       preempt_conditional_cli(regs);
-       return;
-
-clear_TF_reenable:
-       set_tsk_thread_flag(tsk, TIF_SINGLESTEP);
-       regs->flags &= ~X86_EFLAGS_TF;
-       preempt_conditional_cli(regs);
-       return;
-}
-
-static int kernel_math_error(struct pt_regs *regs, const char *str, int trapnr)
-{
-       if (fixup_exception(regs))
-               return 1;
-
-       notify_die(DIE_GPF, str, regs, 0, trapnr, SIGFPE);
-       /* Illegal floating point operation in the kernel */
-       current->thread.trap_no = trapnr;
-       die(str, regs, 0);
-       return 0;
-}
-
-/*
- * Note that we play around with the 'TS' bit in an attempt to get
- * the correct behaviour even in the presence of the asynchronous
- * IRQ13 behaviour
- */
-asmlinkage void do_coprocessor_error(struct pt_regs *regs)
-{
-       void __user *ip = (void __user *)(regs->ip);
-       struct task_struct *task;
-       siginfo_t info;
-       unsigned short cwd, swd;
-
-       conditional_sti(regs);
-       if (!user_mode(regs) &&
-           kernel_math_error(regs, "kernel x87 math error", 16))
-               return;
-
-       /*
-        * Save the info for the exception handler and clear the error.
-        */
-       task = current;
-       save_init_fpu(task);
-       task->thread.trap_no = 16;
-       task->thread.error_code = 0;
-       info.si_signo = SIGFPE;
-       info.si_errno = 0;
-       info.si_code = __SI_FAULT;
-       info.si_addr = ip;
-       /*
-        * (~cwd & swd) will mask out exceptions that are not set to unmasked
-        * status.  0x3f is the exception bits in these regs, 0x200 is the
-        * C1 reg you need in case of a stack fault, 0x040 is the stack
-        * fault bit.  We should only be taking one exception at a time,
-        * so if this combination doesn't produce any single exception,
-        * then we have a bad program that isn't synchronizing its FPU usage
-        * and it will suffer the consequences since we won't be able to
-        * fully reproduce the context of the exception
-        */
-       cwd = get_fpu_cwd(task);
-       swd = get_fpu_swd(task);
-       switch (swd & ~cwd & 0x3f) {
-       case 0x000: /* No unmasked exception */
-       default: /* Multiple exceptions */
-               break;
-       case 0x001: /* Invalid Op */
-               /*
-                * swd & 0x240 == 0x040: Stack Underflow
-                * swd & 0x240 == 0x240: Stack Overflow
-                * User must clear the SF bit (0x40) if set
-                */
-               info.si_code = FPE_FLTINV;
-               break;
-       case 0x002: /* Denormalize */
-       case 0x010: /* Underflow */
-               info.si_code = FPE_FLTUND;
-               break;
-       case 0x004: /* Zero Divide */
-               info.si_code = FPE_FLTDIV;
-               break;
-       case 0x008: /* Overflow */
-               info.si_code = FPE_FLTOVF;
-               break;
-       case 0x020: /* Precision */
-               info.si_code = FPE_FLTRES;
-               break;
-       }
-       force_sig_info(SIGFPE, &info, task);
-}
-
-asmlinkage void bad_intr(void)
-{
-       printk("bad interrupt");
-}
-
-asmlinkage void do_simd_coprocessor_error(struct pt_regs *regs)
-{
-       void __user *ip = (void __user *)(regs->ip);
-       struct task_struct *task;
-       siginfo_t info;
-       unsigned short mxcsr;
-
-       conditional_sti(regs);
-       if (!user_mode(regs) &&
-                       kernel_math_error(regs, "kernel simd math error", 19))
-               return;
-
-       /*
-        * Save the info for the exception handler and clear the error.
-        */
-       task = current;
-       save_init_fpu(task);
-       task->thread.trap_no = 19;
-       task->thread.error_code = 0;
-       info.si_signo = SIGFPE;
-       info.si_errno = 0;
-       info.si_code = __SI_FAULT;
-       info.si_addr = ip;
-       /*
-        * The SIMD FPU exceptions are handled a little differently, as there
-        * is only a single status/control register.  Thus, to determine which
-        * unmasked exception was caught we must mask the exception mask bits
-        * at 0x1f80, and then use these to mask the exception bits at 0x3f.
-        */
-       mxcsr = get_fpu_mxcsr(task);
-       switch (~((mxcsr & 0x1f80) >> 7) & (mxcsr & 0x3f)) {
-       case 0x000:
-       default:
-               break;
-       case 0x001: /* Invalid Op */
-               info.si_code = FPE_FLTINV;
-               break;
-       case 0x002: /* Denormalize */
-       case 0x010: /* Underflow */
-               info.si_code = FPE_FLTUND;
-               break;
-       case 0x004: /* Zero Divide */
-               info.si_code = FPE_FLTDIV;
-               break;
-       case 0x008: /* Overflow */
-               info.si_code = FPE_FLTOVF;
-               break;
-       case 0x020: /* Precision */
-               info.si_code = FPE_FLTRES;
-               break;
-       }
-       force_sig_info(SIGFPE, &info, task);
-}
-
-asmlinkage void do_spurious_interrupt_bug(struct pt_regs *regs)
-{
-}
-
-asmlinkage void __attribute__((weak)) smp_thermal_interrupt(void)
-{
-}
-
-asmlinkage void __attribute__((weak)) mce_threshold_interrupt(void)
-{
-}
-
-/*
- * 'math_state_restore()' saves the current math information in the
- * old math state array, and gets the new ones from the current task
- *
- * Careful.. There are problems with IBM-designed IRQ13 behaviour.
- * Don't touch unless you *really* know how it works.
- */
-asmlinkage void math_state_restore(void)
-{
-       struct task_struct *me = current;
-
-       if (!used_math()) {
-               local_irq_enable();
-               /*
-                * does a slab alloc which can sleep
-                */
-               if (init_fpu(me)) {
-                       /*
-                        * ran out of memory!
-                        */
-                       do_group_exit(SIGKILL);
-                       return;
-               }
-               local_irq_disable();
-       }
-
-       clts();                         /* Allow maths ops (or we recurse) */
-       /*
-        * Paranoid restore. send a SIGSEGV if we fail to restore the state.
-        */
-       if (unlikely(restore_fpu_checking(me))) {
-               stts();
-               force_sig(SIGSEGV, me);
-               return;
-       }
-       task_thread_info(me)->status |= TS_USEDFPU;
-       me->fpu_counter++;
-}
-EXPORT_SYMBOL_GPL(math_state_restore);
-
-void __init trap_init(void)
-{
-       set_intr_gate(0, &divide_error);
-       set_intr_gate_ist(1, &debug, DEBUG_STACK);
-       set_intr_gate_ist(2, &nmi, NMI_STACK);
-       /* int3 can be called from all */
-       set_system_gate_ist(3, &int3, DEBUG_STACK);
-       /* int4 can be called from all */
-       set_system_gate(4, &overflow);
-       set_intr_gate(5, &bounds);
-       set_intr_gate(6, &invalid_op);
-       set_intr_gate(7, &device_not_available);
-       set_intr_gate_ist(8, &double_fault, DOUBLEFAULT_STACK);
-       set_intr_gate(9, &coprocessor_segment_overrun);
-       set_intr_gate(10, &invalid_TSS);
-       set_intr_gate(11, &segment_not_present);
-       set_intr_gate_ist(12, &stack_segment, STACKFAULT_STACK);
-       set_intr_gate(13, &general_protection);
-       set_intr_gate(14, &page_fault);
-       set_intr_gate(15, &spurious_interrupt_bug);
-       set_intr_gate(16, &coprocessor_error);
-       set_intr_gate(17, &alignment_check);
-#ifdef CONFIG_X86_MCE
-       set_intr_gate_ist(18, &machine_check, MCE_STACK);
-#endif
-       set_intr_gate(19, &simd_coprocessor_error);
-
-#ifdef CONFIG_IA32_EMULATION
-       set_system_gate(IA32_SYSCALL_VECTOR, ia32_syscall);
-#endif
-       /*
-        * Should be a barrier for any external CPU state:
-        */
-       cpu_init();
-}
-
-static int __init oops_setup(char *s)
-{
-       if (!s)
-               return -EINVAL;
-       if (!strcmp(s, "panic"))
-               panic_on_oops = 1;
-       return 0;
-}
-early_param("oops", oops_setup);
-
-static int __init kstack_setup(char *s)
-{
-       if (!s)
-               return -EINVAL;
-       kstack_depth_to_print = simple_strtoul(s, NULL, 0);
-       return 0;
-}
-early_param("kstack", kstack_setup);
-
-static int __init code_bytes_setup(char *s)
-{
-       code_bytes = simple_strtoul(s, NULL, 0);
-       if (code_bytes > 8192)
-               code_bytes = 8192;
-
-       return 1;
-}
-__setup("code_bytes=", code_bytes_setup);
index 520cca0ee04e382227acb882ebd3a0665a5135b8..6513d41ea21eb54d84aa3c7720afaf7671f27d8e 100644 (file)
@@ -47,16 +47,26 @@ static __init int mps_oem_check(struct mp_config_table *mpc, char *oem,
 /* Hook from generic ACPI tables.c */
 static int __init acpi_madt_oem_check(char *oem_id, char *oem_table_id)
 {
-       unsigned long oem_addr;
+       unsigned long oem_addr = 0;
+       int check_dsdt;
+       int ret = 0;
+
+       /* check dsdt at first to avoid clear fix_map for oem_addr */
+       check_dsdt = es7000_check_dsdt();
+
        if (!find_unisys_acpi_oem_table(&oem_addr)) {
-               if (es7000_check_dsdt())
-                       return parse_unisys_oem((char *)oem_addr);
+               if (check_dsdt)
+                       ret = parse_unisys_oem((char *)oem_addr);
                else {
                        setup_unisys();
-                       return 1;
+                       ret = 1;
                }
+               /*
+                * we need to unmap it
+                */
+               unmap_unisys_acpi_oem_table(oem_addr);
        }
-       return 0;
+       return ret;
 }
 #else
 static int __init acpi_madt_oem_check(char *oem_id, char *oem_table_id)
index dfb932dcf136c5055dd555d6e5680e4821bacf59..59f89b434b45fbb80df02bafe3f54122a8738b50 100644 (file)
@@ -13,12 +13,8 @@ obj-$(CONFIG_MMIOTRACE)              += mmiotrace.o
 mmiotrace-y                    := pf_in.o mmio-mod.o
 obj-$(CONFIG_MMIOTRACE_TEST)   += testmmiotrace.o
 
-ifeq ($(CONFIG_X86_32),y)
-obj-$(CONFIG_NUMA)             += discontig_32.o
-else
-obj-$(CONFIG_NUMA)             += numa_64.o
+obj-$(CONFIG_NUMA)             += numa_$(BITS).o
 obj-$(CONFIG_K8_NUMA)          += k8topology_64.o
-endif
 obj-$(CONFIG_ACPI_NUMA)                += srat_$(BITS).o
 
 obj-$(CONFIG_MEMTEST)          += memtest.o
index a742d753d5b0ae438a65e976354556a8b0c938b1..3f2b8962cbd0f71223ed8dfed8f90b893a966349 100644 (file)
@@ -592,11 +592,6 @@ void __kprobes do_page_fault(struct pt_regs *regs, unsigned long error_code)
        unsigned long flags;
 #endif
 
-       /*
-        * We can fault from pretty much anywhere, with unknown IRQ state.
-        */
-       trace_hardirqs_fixup();
-
        tsk = current;
        mm = tsk->mm;
        prefetchw(&mm->mmap_sem);
index 007bb06c750477b60c158f667f5d0563c2d77433..4ba373c5b8c8b94eec4902f2ec3f1448b8b1f6af 100644 (file)
@@ -82,7 +82,7 @@ static noinline int gup_pte_range(pmd_t pmd, unsigned long addr,
                pte_t pte = gup_get_pte(ptep);
                struct page *page;
 
-               if ((pte_val(pte) & (mask | _PAGE_SPECIAL)) != mask) {
+               if ((pte_flags(pte) & (mask | _PAGE_SPECIAL)) != mask) {
                        pte_unmap(ptep);
                        return 0;
                }
@@ -116,10 +116,10 @@ static noinline int gup_huge_pmd(pmd_t pmd, unsigned long addr,
        mask = _PAGE_PRESENT|_PAGE_USER;
        if (write)
                mask |= _PAGE_RW;
-       if ((pte_val(pte) & mask) != mask)
+       if ((pte_flags(pte) & mask) != mask)
                return 0;
        /* hugepages are never "special" */
-       VM_BUG_ON(pte_val(pte) & _PAGE_SPECIAL);
+       VM_BUG_ON(pte_flags(pte) & _PAGE_SPECIAL);
        VM_BUG_ON(!pfn_valid(pte_pfn(pte)));
 
        refs = 0;
@@ -173,10 +173,10 @@ static noinline int gup_huge_pud(pud_t pud, unsigned long addr,
        mask = _PAGE_PRESENT|_PAGE_USER;
        if (write)
                mask |= _PAGE_RW;
-       if ((pte_val(pte) & mask) != mask)
+       if ((pte_flags(pte) & mask) != mask)
                return 0;
        /* hugepages are never "special" */
-       VM_BUG_ON(pte_val(pte) & _PAGE_SPECIAL);
+       VM_BUG_ON(pte_flags(pte) & _PAGE_SPECIAL);
        VM_BUG_ON(!pfn_valid(pte_pfn(pte)));
 
        refs = 0;
index bbe044dbe01403b0bdf67dbf4fe7e46e4e00a07e..8396868e82c5637772f8d9fe81129731f87d2e24 100644 (file)
@@ -558,7 +558,7 @@ void zap_low_mappings(void)
 
 int nx_enabled;
 
-pteval_t __supported_pte_mask __read_mostly = ~(_PAGE_NX | _PAGE_GLOBAL);
+pteval_t __supported_pte_mask __read_mostly = ~(_PAGE_NX | _PAGE_GLOBAL | _PAGE_IOMAP);
 EXPORT_SYMBOL_GPL(__supported_pte_mask);
 
 #ifdef CONFIG_X86_PAE
index 3e10054c57319c25626bd1f43bf830c11453b255..b8e461d4941208fab60f977471dbe088ce48d23e 100644 (file)
@@ -89,7 +89,7 @@ early_param("gbpages", parse_direct_gbpages_on);
 
 int after_bootmem;
 
-unsigned long __supported_pte_mask __read_mostly = ~0UL;
+pteval_t __supported_pte_mask __read_mostly = ~_PAGE_IOMAP;
 EXPORT_SYMBOL_GPL(__supported_pte_mask);
 
 static int do_not_nx __cpuinitdata;
@@ -196,9 +196,6 @@ set_pte_vaddr_pud(pud_t *pud_page, unsigned long vaddr, pte_t new_pte)
        }
 
        pte = pte_offset_kernel(pmd, vaddr);
-       if (!pte_none(*pte) && pte_val(new_pte) &&
-           pte_val(*pte) != (pte_val(new_pte) & __supported_pte_mask))
-               pte_ERROR(*pte);
        set_pte(pte, new_pte);
 
        /*
@@ -313,7 +310,7 @@ static __ref void *alloc_low_page(unsigned long *phys)
        if (pfn >= table_top)
                panic("alloc_low_page: ran out of memory");
 
-       adr = early_ioremap(pfn * PAGE_SIZE, PAGE_SIZE);
+       adr = early_memremap(pfn * PAGE_SIZE, PAGE_SIZE);
        memset(adr, 0, PAGE_SIZE);
        *phys  = pfn * PAGE_SIZE;
        return adr;
@@ -749,7 +746,7 @@ unsigned long __init_refok init_memory_mapping(unsigned long start,
                old_start = mr[i].start;
                memmove(&mr[i], &mr[i+1],
                         (nr_range - 1 - i) * sizeof (struct map_range));
-               mr[i].start = old_start;
+               mr[i--].start = old_start;
                nr_range--;
        }
 
index 8cbeda15cd29727bee40bc4f15de3a8fd3b573b2..e4c43ec71b29ebeb40a40b63cd7f4394fb448b0a 100644 (file)
@@ -45,6 +45,27 @@ unsigned long __phys_addr(unsigned long x)
 }
 EXPORT_SYMBOL(__phys_addr);
 
+bool __virt_addr_valid(unsigned long x)
+{
+       if (x >= __START_KERNEL_map) {
+               x -= __START_KERNEL_map;
+               if (x >= KERNEL_IMAGE_SIZE)
+                       return false;
+               x += phys_base;
+       } else {
+               if (x < PAGE_OFFSET)
+                       return false;
+               x -= PAGE_OFFSET;
+               if (system_state == SYSTEM_BOOTING ?
+                               x > MAXMEM : !phys_addr_valid(x)) {
+                       return false;
+               }
+       }
+
+       return pfn_valid(x >> PAGE_SHIFT);
+}
+EXPORT_SYMBOL(__virt_addr_valid);
+
 #else
 
 static inline int phys_addr_valid(unsigned long addr)
@@ -56,13 +77,24 @@ static inline int phys_addr_valid(unsigned long addr)
 unsigned long __phys_addr(unsigned long x)
 {
        /* VMALLOC_* aren't constants; not available at the boot time */
-       VIRTUAL_BUG_ON(x < PAGE_OFFSET || (system_state != SYSTEM_BOOTING &&
-                                       is_vmalloc_addr((void *)x)));
+       VIRTUAL_BUG_ON(x < PAGE_OFFSET);
+       VIRTUAL_BUG_ON(system_state != SYSTEM_BOOTING &&
+               is_vmalloc_addr((void *) x));
        return x - PAGE_OFFSET;
 }
 EXPORT_SYMBOL(__phys_addr);
 #endif
 
+bool __virt_addr_valid(unsigned long x)
+{
+       if (x < PAGE_OFFSET)
+               return false;
+       if (system_state != SYSTEM_BOOTING && is_vmalloc_addr((void *) x))
+               return false;
+       return pfn_valid((x - PAGE_OFFSET) >> PAGE_SHIFT);
+}
+EXPORT_SYMBOL(__virt_addr_valid);
+
 #endif
 
 int page_is_ram(unsigned long pagenr)
@@ -242,16 +274,16 @@ static void __iomem *__ioremap_caller(resource_size_t phys_addr,
        switch (prot_val) {
        case _PAGE_CACHE_UC:
        default:
-               prot = PAGE_KERNEL_NOCACHE;
+               prot = PAGE_KERNEL_IO_NOCACHE;
                break;
        case _PAGE_CACHE_UC_MINUS:
-               prot = PAGE_KERNEL_UC_MINUS;
+               prot = PAGE_KERNEL_IO_UC_MINUS;
                break;
        case _PAGE_CACHE_WC:
-               prot = PAGE_KERNEL_WC;
+               prot = PAGE_KERNEL_IO_WC;
                break;
        case _PAGE_CACHE_WB:
-               prot = PAGE_KERNEL;
+               prot = PAGE_KERNEL_IO;
                break;
        }
 
@@ -568,12 +600,12 @@ static void __init __early_set_fixmap(enum fixed_addresses idx,
 }
 
 static inline void __init early_set_fixmap(enum fixed_addresses idx,
-                                       unsigned long phys)
+                                          unsigned long phys, pgprot_t prot)
 {
        if (after_paging_init)
-               set_fixmap(idx, phys);
+               __set_fixmap(idx, phys, prot);
        else
-               __early_set_fixmap(idx, phys, PAGE_KERNEL);
+               __early_set_fixmap(idx, phys, prot);
 }
 
 static inline void __init early_clear_fixmap(enum fixed_addresses idx)
@@ -584,16 +616,22 @@ static inline void __init early_clear_fixmap(enum fixed_addresses idx)
                __early_set_fixmap(idx, 0, __pgprot(0));
 }
 
-
-static int __initdata early_ioremap_nested;
-
+static void *prev_map[FIX_BTMAPS_SLOTS] __initdata;
+static unsigned long prev_size[FIX_BTMAPS_SLOTS] __initdata;
 static int __init check_early_ioremap_leak(void)
 {
-       if (!early_ioremap_nested)
+       int count = 0;
+       int i;
+
+       for (i = 0; i < FIX_BTMAPS_SLOTS; i++)
+               if (prev_map[i])
+                       count++;
+
+       if (!count)
                return 0;
        WARN(1, KERN_WARNING
               "Debug warning: early ioremap leak of %d areas detected.\n",
-               early_ioremap_nested);
+               count);
        printk(KERN_WARNING
                "please boot with early_ioremap_debug and report the dmesg.\n");
 
@@ -601,18 +639,33 @@ static int __init check_early_ioremap_leak(void)
 }
 late_initcall(check_early_ioremap_leak);
 
-void __init *early_ioremap(unsigned long phys_addr, unsigned long size)
+static void __init *__early_ioremap(unsigned long phys_addr, unsigned long size, pgprot_t prot)
 {
        unsigned long offset, last_addr;
-       unsigned int nrpages, nesting;
+       unsigned int nrpages;
        enum fixed_addresses idx0, idx;
+       int i, slot;
 
        WARN_ON(system_state != SYSTEM_BOOTING);
 
-       nesting = early_ioremap_nested;
+       slot = -1;
+       for (i = 0; i < FIX_BTMAPS_SLOTS; i++) {
+               if (!prev_map[i]) {
+                       slot = i;
+                       break;
+               }
+       }
+
+       if (slot < 0) {
+               printk(KERN_INFO "early_iomap(%08lx, %08lx) not found slot\n",
+                        phys_addr, size);
+               WARN_ON(1);
+               return NULL;
+       }
+
        if (early_ioremap_debug) {
                printk(KERN_INFO "early_ioremap(%08lx, %08lx) [%d] => ",
-                      phys_addr, size, nesting);
+                      phys_addr, size, slot);
                dump_stack();
        }
 
@@ -623,11 +676,7 @@ void __init *early_ioremap(unsigned long phys_addr, unsigned long size)
                return NULL;
        }
 
-       if (nesting >= FIX_BTMAPS_NESTING) {
-               WARN_ON(1);
-               return NULL;
-       }
-       early_ioremap_nested++;
+       prev_size[slot] = size;
        /*
         * Mappings have to be page-aligned
         */
@@ -647,10 +696,10 @@ void __init *early_ioremap(unsigned long phys_addr, unsigned long size)
        /*
         * Ok, go for it..
         */
-       idx0 = FIX_BTMAP_BEGIN - NR_FIX_BTMAPS*nesting;
+       idx0 = FIX_BTMAP_BEGIN - NR_FIX_BTMAPS*slot;
        idx = idx0;
        while (nrpages > 0) {
-               early_set_fixmap(idx, phys_addr);
+               early_set_fixmap(idx, phys_addr, prot);
                phys_addr += PAGE_SIZE;
                --idx;
                --nrpages;
@@ -658,7 +707,20 @@ void __init *early_ioremap(unsigned long phys_addr, unsigned long size)
        if (early_ioremap_debug)
                printk(KERN_CONT "%08lx + %08lx\n", offset, fix_to_virt(idx0));
 
-       return (void *) (offset + fix_to_virt(idx0));
+       prev_map[slot] = (void *) (offset + fix_to_virt(idx0));
+       return prev_map[slot];
+}
+
+/* Remap an IO device */
+void __init *early_ioremap(unsigned long phys_addr, unsigned long size)
+{
+       return __early_ioremap(phys_addr, size, PAGE_KERNEL_IO);
+}
+
+/* Remap memory */
+void __init *early_memremap(unsigned long phys_addr, unsigned long size)
+{
+       return __early_ioremap(phys_addr, size, PAGE_KERNEL);
 }
 
 void __init early_iounmap(void *addr, unsigned long size)
@@ -667,15 +729,33 @@ void __init early_iounmap(void *addr, unsigned long size)
        unsigned long offset;
        unsigned int nrpages;
        enum fixed_addresses idx;
-       int nesting;
+       int i, slot;
+
+       slot = -1;
+       for (i = 0; i < FIX_BTMAPS_SLOTS; i++) {
+               if (prev_map[i] == addr) {
+                       slot = i;
+                       break;
+               }
+       }
 
-       nesting = --early_ioremap_nested;
-       if (WARN_ON(nesting < 0))
+       if (slot < 0) {
+               printk(KERN_INFO "early_iounmap(%p, %08lx) not found slot\n",
+                        addr, size);
+               WARN_ON(1);
+               return;
+       }
+
+       if (prev_size[slot] != size) {
+               printk(KERN_INFO "early_iounmap(%p, %08lx) [%d] size not consistent %08lx\n",
+                        addr, size, slot, prev_size[slot]);
+               WARN_ON(1);
                return;
+       }
 
        if (early_ioremap_debug) {
                printk(KERN_INFO "early_iounmap(%p, %08lx) [%d]\n", addr,
-                      size, nesting);
+                      size, slot);
                dump_stack();
        }
 
@@ -687,12 +767,13 @@ void __init early_iounmap(void *addr, unsigned long size)
        offset = virt_addr & ~PAGE_MASK;
        nrpages = PAGE_ALIGN(offset + size - 1) >> PAGE_SHIFT;
 
-       idx = FIX_BTMAP_BEGIN - NR_FIX_BTMAPS*nesting;
+       idx = FIX_BTMAP_BEGIN - NR_FIX_BTMAPS*slot;
        while (nrpages > 0) {
                early_clear_fixmap(idx);
                --idx;
                --nrpages;
        }
+       prev_map[slot] = 0;
 }
 
 void __this_fixmap_does_not_exist(void)
index 1b4763e26ea96f52b6240475e85a04cb3a06dc4b..51c0a2fc14fe05521def4af57c0e2d1d29c8359d 100644 (file)
@@ -138,7 +138,7 @@ acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *pa)
                return;
        }
 
-       if (is_uv_system())
+       if (get_uv_system_type() >= UV_X2APIC)
                apic_id = (pa->apic_id << 8) | pa->local_sapic_eid;
        else
                apic_id = pa->apic_id;
index 30f3eb3666675e4b8a90bff8f0edfd43cfe99f6f..446902b2a6b6a2fac5080d062e8d86b1caea8aae 100644 (file)
@@ -7,6 +7,6 @@ DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \
                timer_int.o )
 
 oprofile-y                             := $(DRIVER_OBJS) init.o backtrace.o
-oprofile-$(CONFIG_X86_LOCAL_APIC)      += nmi_int.o op_model_athlon.o \
+oprofile-$(CONFIG_X86_LOCAL_APIC)      += nmi_int.o op_model_amd.o \
                                           op_model_ppro.o op_model_p4.o
 oprofile-$(CONFIG_X86_IO_APIC)         += nmi_timer_int.o
index 8a5f1614a3d57cde8d7495c1b71f8e8542e99c64..57f6c90880816b113074cf306f678f8781c04d50 100644 (file)
@@ -1,10 +1,11 @@
 /**
  * @file nmi_int.c
  *
- * @remark Copyright 2002 OProfile authors
+ * @remark Copyright 2002-2008 OProfile authors
  * @remark Read the file COPYING
  *
  * @author John Levon <levon@movementarian.org>
+ * @author Robert Richter <robert.richter@amd.com>
  */
 
 #include <linux/init.h>
@@ -439,6 +440,7 @@ int __init op_nmi_init(struct oprofile_operations *ops)
        __u8 vendor = boot_cpu_data.x86_vendor;
        __u8 family = boot_cpu_data.x86;
        char *cpu_type;
+       int ret = 0;
 
        if (!cpu_has_apic)
                return -ENODEV;
@@ -451,19 +453,23 @@ int __init op_nmi_init(struct oprofile_operations *ops)
                default:
                        return -ENODEV;
                case 6:
-                       model = &op_athlon_spec;
+                       model = &op_amd_spec;
                        cpu_type = "i386/athlon";
                        break;
                case 0xf:
-                       model = &op_athlon_spec;
+                       model = &op_amd_spec;
                        /* Actually it could be i386/hammer too, but give
                         user space an consistent name. */
                        cpu_type = "x86-64/hammer";
                        break;
                case 0x10:
-                       model = &op_athlon_spec;
+                       model = &op_amd_spec;
                        cpu_type = "x86-64/family10";
                        break;
+               case 0x11:
+                       model = &op_amd_spec;
+                       cpu_type = "x86-64/family11h";
+                       break;
                }
                break;
 
@@ -490,17 +496,24 @@ int __init op_nmi_init(struct oprofile_operations *ops)
                return -ENODEV;
        }
 
-       init_sysfs();
 #ifdef CONFIG_SMP
        register_cpu_notifier(&oprofile_cpu_nb);
 #endif
-       using_nmi = 1;
+       /* default values, can be overwritten by model */
        ops->create_files = nmi_create_files;
        ops->setup = nmi_setup;
        ops->shutdown = nmi_shutdown;
        ops->start = nmi_start;
        ops->stop = nmi_stop;
        ops->cpu_type = cpu_type;
+
+       if (model->init)
+               ret = model->init(ops);
+       if (ret)
+               return ret;
+
+       init_sysfs();
+       using_nmi = 1;
        printk(KERN_INFO "oprofile: using NMI interrupt.\n");
        return 0;
 }
@@ -513,4 +526,6 @@ void op_nmi_exit(void)
                unregister_cpu_notifier(&oprofile_cpu_nb);
 #endif
        }
+       if (model->exit)
+               model->exit();
 }
diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c
new file mode 100644 (file)
index 0000000..d9faf60
--- /dev/null
@@ -0,0 +1,543 @@
+/*
+ * @file op_model_amd.c
+ * athlon / K7 / K8 / Family 10h model-specific MSR operations
+ *
+ * @remark Copyright 2002-2008 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author John Levon
+ * @author Philippe Elie
+ * @author Graydon Hoare
+ * @author Robert Richter <robert.richter@amd.com>
+ * @author Barry Kasindorf
+*/
+
+#include <linux/oprofile.h>
+#include <linux/device.h>
+#include <linux/pci.h>
+
+#include <asm/ptrace.h>
+#include <asm/msr.h>
+#include <asm/nmi.h>
+
+#include "op_x86_model.h"
+#include "op_counter.h"
+
+#define NUM_COUNTERS 4
+#define NUM_CONTROLS 4
+
+#define CTR_IS_RESERVED(msrs, c) (msrs->counters[(c)].addr ? 1 : 0)
+#define CTR_READ(l, h, msrs, c) do {rdmsr(msrs->counters[(c)].addr, (l), (h)); } while (0)
+#define CTR_WRITE(l, msrs, c) do {wrmsr(msrs->counters[(c)].addr, -(unsigned int)(l), -1); } while (0)
+#define CTR_OVERFLOWED(n) (!((n) & (1U<<31)))
+
+#define CTRL_IS_RESERVED(msrs, c) (msrs->controls[(c)].addr ? 1 : 0)
+#define CTRL_READ(l, h, msrs, c) do {rdmsr(msrs->controls[(c)].addr, (l), (h)); } while (0)
+#define CTRL_WRITE(l, h, msrs, c) do {wrmsr(msrs->controls[(c)].addr, (l), (h)); } while (0)
+#define CTRL_SET_ACTIVE(n) (n |= (1<<22))
+#define CTRL_SET_INACTIVE(n) (n &= ~(1<<22))
+#define CTRL_CLEAR_LO(x) (x &= (1<<21))
+#define CTRL_CLEAR_HI(x) (x &= 0xfffffcf0)
+#define CTRL_SET_ENABLE(val) (val |= 1<<20)
+#define CTRL_SET_USR(val, u) (val |= ((u & 1) << 16))
+#define CTRL_SET_KERN(val, k) (val |= ((k & 1) << 17))
+#define CTRL_SET_UM(val, m) (val |= (m << 8))
+#define CTRL_SET_EVENT_LOW(val, e) (val |= (e & 0xff))
+#define CTRL_SET_EVENT_HIGH(val, e) (val |= ((e >> 8) & 0xf))
+#define CTRL_SET_HOST_ONLY(val, h) (val |= ((h & 1) << 9))
+#define CTRL_SET_GUEST_ONLY(val, h) (val |= ((h & 1) << 8))
+
+static unsigned long reset_value[NUM_COUNTERS];
+
+#ifdef CONFIG_OPROFILE_IBS
+
+/* IbsFetchCtl bits/masks */
+#define IBS_FETCH_HIGH_VALID_BIT       (1UL << 17)     /* bit 49 */
+#define IBS_FETCH_HIGH_ENABLE          (1UL << 16)     /* bit 48 */
+#define IBS_FETCH_LOW_MAX_CNT_MASK     0x0000FFFFUL    /* MaxCnt mask */
+
+/*IbsOpCtl bits */
+#define IBS_OP_LOW_VALID_BIT           (1ULL<<18)      /* bit 18 */
+#define IBS_OP_LOW_ENABLE              (1ULL<<17)      /* bit 17 */
+
+/* Codes used in cpu_buffer.c */
+/* This produces duplicate code, need to be fixed */
+#define IBS_FETCH_BEGIN 3
+#define IBS_OP_BEGIN    4
+
+/* The function interface needs to be fixed, something like add
+   data. Should then be added to linux/oprofile.h. */
+extern void oprofile_add_ibs_sample(struct pt_regs *const regs,
+                                   unsigned int * const ibs_sample, u8 code);
+
+struct ibs_fetch_sample {
+       /* MSRC001_1031 IBS Fetch Linear Address Register */
+       unsigned int ibs_fetch_lin_addr_low;
+       unsigned int ibs_fetch_lin_addr_high;
+       /* MSRC001_1030 IBS Fetch Control Register */
+       unsigned int ibs_fetch_ctl_low;
+       unsigned int ibs_fetch_ctl_high;
+       /* MSRC001_1032 IBS Fetch Physical Address Register */
+       unsigned int ibs_fetch_phys_addr_low;
+       unsigned int ibs_fetch_phys_addr_high;
+};
+
+struct ibs_op_sample {
+       /* MSRC001_1034 IBS Op Logical Address Register (IbsRIP) */
+       unsigned int ibs_op_rip_low;
+       unsigned int ibs_op_rip_high;
+       /* MSRC001_1035 IBS Op Data Register */
+       unsigned int ibs_op_data1_low;
+       unsigned int ibs_op_data1_high;
+       /* MSRC001_1036 IBS Op Data 2 Register */
+       unsigned int ibs_op_data2_low;
+       unsigned int ibs_op_data2_high;
+       /* MSRC001_1037 IBS Op Data 3 Register */
+       unsigned int ibs_op_data3_low;
+       unsigned int ibs_op_data3_high;
+       /* MSRC001_1038 IBS DC Linear Address Register (IbsDcLinAd) */
+       unsigned int ibs_dc_linear_low;
+       unsigned int ibs_dc_linear_high;
+       /* MSRC001_1039 IBS DC Physical Address Register (IbsDcPhysAd) */
+       unsigned int ibs_dc_phys_low;
+       unsigned int ibs_dc_phys_high;
+};
+
+/*
+ * unitialize the APIC for the IBS interrupts if needed on AMD Family10h+
+*/
+static void clear_ibs_nmi(void);
+
+static int ibs_allowed;        /* AMD Family10h and later */
+
+struct op_ibs_config {
+       unsigned long op_enabled;
+       unsigned long fetch_enabled;
+       unsigned long max_cnt_fetch;
+       unsigned long max_cnt_op;
+       unsigned long rand_en;
+       unsigned long dispatched_ops;
+};
+
+static struct op_ibs_config ibs_config;
+
+#endif
+
+/* functions for op_amd_spec */
+
+static void op_amd_fill_in_addresses(struct op_msrs * const msrs)
+{
+       int i;
+
+       for (i = 0; i < NUM_COUNTERS; i++) {
+               if (reserve_perfctr_nmi(MSR_K7_PERFCTR0 + i))
+                       msrs->counters[i].addr = MSR_K7_PERFCTR0 + i;
+               else
+                       msrs->counters[i].addr = 0;
+       }
+
+       for (i = 0; i < NUM_CONTROLS; i++) {
+               if (reserve_evntsel_nmi(MSR_K7_EVNTSEL0 + i))
+                       msrs->controls[i].addr = MSR_K7_EVNTSEL0 + i;
+               else
+                       msrs->controls[i].addr = 0;
+       }
+}
+
+
+static void op_amd_setup_ctrs(struct op_msrs const * const msrs)
+{
+       unsigned int low, high;
+       int i;
+
+       /* clear all counters */
+       for (i = 0 ; i < NUM_CONTROLS; ++i) {
+               if (unlikely(!CTRL_IS_RESERVED(msrs, i)))
+                       continue;
+               CTRL_READ(low, high, msrs, i);
+               CTRL_CLEAR_LO(low);
+               CTRL_CLEAR_HI(high);
+               CTRL_WRITE(low, high, msrs, i);
+       }
+
+       /* avoid a false detection of ctr overflows in NMI handler */
+       for (i = 0; i < NUM_COUNTERS; ++i) {
+               if (unlikely(!CTR_IS_RESERVED(msrs, i)))
+                       continue;
+               CTR_WRITE(1, msrs, i);
+       }
+
+       /* enable active counters */
+       for (i = 0; i < NUM_COUNTERS; ++i) {
+               if ((counter_config[i].enabled) && (CTR_IS_RESERVED(msrs, i))) {
+                       reset_value[i] = counter_config[i].count;
+
+                       CTR_WRITE(counter_config[i].count, msrs, i);
+
+                       CTRL_READ(low, high, msrs, i);
+                       CTRL_CLEAR_LO(low);
+                       CTRL_CLEAR_HI(high);
+                       CTRL_SET_ENABLE(low);
+                       CTRL_SET_USR(low, counter_config[i].user);
+                       CTRL_SET_KERN(low, counter_config[i].kernel);
+                       CTRL_SET_UM(low, counter_config[i].unit_mask);
+                       CTRL_SET_EVENT_LOW(low, counter_config[i].event);
+                       CTRL_SET_EVENT_HIGH(high, counter_config[i].event);
+                       CTRL_SET_HOST_ONLY(high, 0);
+                       CTRL_SET_GUEST_ONLY(high, 0);
+
+                       CTRL_WRITE(low, high, msrs, i);
+               } else {
+                       reset_value[i] = 0;
+               }
+       }
+}
+
+#ifdef CONFIG_OPROFILE_IBS
+
+static inline int
+op_amd_handle_ibs(struct pt_regs * const regs,
+                 struct op_msrs const * const msrs)
+{
+       unsigned int low, high;
+       struct ibs_fetch_sample ibs_fetch;
+       struct ibs_op_sample ibs_op;
+
+       if (!ibs_allowed)
+               return 1;
+
+       if (ibs_config.fetch_enabled) {
+               rdmsr(MSR_AMD64_IBSFETCHCTL, low, high);
+               if (high & IBS_FETCH_HIGH_VALID_BIT) {
+                       ibs_fetch.ibs_fetch_ctl_high = high;
+                       ibs_fetch.ibs_fetch_ctl_low = low;
+                       rdmsr(MSR_AMD64_IBSFETCHLINAD, low, high);
+                       ibs_fetch.ibs_fetch_lin_addr_high = high;
+                       ibs_fetch.ibs_fetch_lin_addr_low = low;
+                       rdmsr(MSR_AMD64_IBSFETCHPHYSAD, low, high);
+                       ibs_fetch.ibs_fetch_phys_addr_high = high;
+                       ibs_fetch.ibs_fetch_phys_addr_low = low;
+
+                       oprofile_add_ibs_sample(regs,
+                                               (unsigned int *)&ibs_fetch,
+                                               IBS_FETCH_BEGIN);
+
+                       /*reenable the IRQ */
+                       rdmsr(MSR_AMD64_IBSFETCHCTL, low, high);
+                       high &= ~IBS_FETCH_HIGH_VALID_BIT;
+                       high |= IBS_FETCH_HIGH_ENABLE;
+                       low &= IBS_FETCH_LOW_MAX_CNT_MASK;
+                       wrmsr(MSR_AMD64_IBSFETCHCTL, low, high);
+               }
+       }
+
+       if (ibs_config.op_enabled) {
+               rdmsr(MSR_AMD64_IBSOPCTL, low, high);
+               if (low & IBS_OP_LOW_VALID_BIT) {
+                       rdmsr(MSR_AMD64_IBSOPRIP, low, high);
+                       ibs_op.ibs_op_rip_low = low;
+                       ibs_op.ibs_op_rip_high = high;
+                       rdmsr(MSR_AMD64_IBSOPDATA, low, high);
+                       ibs_op.ibs_op_data1_low = low;
+                       ibs_op.ibs_op_data1_high = high;
+                       rdmsr(MSR_AMD64_IBSOPDATA2, low, high);
+                       ibs_op.ibs_op_data2_low = low;
+                       ibs_op.ibs_op_data2_high = high;
+                       rdmsr(MSR_AMD64_IBSOPDATA3, low, high);
+                       ibs_op.ibs_op_data3_low = low;
+                       ibs_op.ibs_op_data3_high = high;
+                       rdmsr(MSR_AMD64_IBSDCLINAD, low, high);
+                       ibs_op.ibs_dc_linear_low = low;
+                       ibs_op.ibs_dc_linear_high = high;
+                       rdmsr(MSR_AMD64_IBSDCPHYSAD, low, high);
+                       ibs_op.ibs_dc_phys_low = low;
+                       ibs_op.ibs_dc_phys_high = high;
+
+                       /* reenable the IRQ */
+                       oprofile_add_ibs_sample(regs,
+                                               (unsigned int *)&ibs_op,
+                                               IBS_OP_BEGIN);
+                       rdmsr(MSR_AMD64_IBSOPCTL, low, high);
+                       high = 0;
+                       low &= ~IBS_OP_LOW_VALID_BIT;
+                       low |= IBS_OP_LOW_ENABLE;
+                       wrmsr(MSR_AMD64_IBSOPCTL, low, high);
+               }
+       }
+
+       return 1;
+}
+
+#endif
+
+static int op_amd_check_ctrs(struct pt_regs * const regs,
+                            struct op_msrs const * const msrs)
+{
+       unsigned int low, high;
+       int i;
+
+       for (i = 0 ; i < NUM_COUNTERS; ++i) {
+               if (!reset_value[i])
+                       continue;
+               CTR_READ(low, high, msrs, i);
+               if (CTR_OVERFLOWED(low)) {
+                       oprofile_add_sample(regs, i);
+                       CTR_WRITE(reset_value[i], msrs, i);
+               }
+       }
+
+#ifdef CONFIG_OPROFILE_IBS
+       op_amd_handle_ibs(regs, msrs);
+#endif
+
+       /* See op_model_ppro.c */
+       return 1;
+}
+
+static void op_amd_start(struct op_msrs const * const msrs)
+{
+       unsigned int low, high;
+       int i;
+       for (i = 0 ; i < NUM_COUNTERS ; ++i) {
+               if (reset_value[i]) {
+                       CTRL_READ(low, high, msrs, i);
+                       CTRL_SET_ACTIVE(low);
+                       CTRL_WRITE(low, high, msrs, i);
+               }
+       }
+
+#ifdef CONFIG_OPROFILE_IBS
+       if (ibs_allowed && ibs_config.fetch_enabled) {
+               low = (ibs_config.max_cnt_fetch >> 4) & 0xFFFF;
+               high = IBS_FETCH_HIGH_ENABLE;
+               wrmsr(MSR_AMD64_IBSFETCHCTL, low, high);
+       }
+
+       if (ibs_allowed && ibs_config.op_enabled) {
+               low = ((ibs_config.max_cnt_op >> 4) & 0xFFFF) + IBS_OP_LOW_ENABLE;
+               high = 0;
+               wrmsr(MSR_AMD64_IBSOPCTL, low, high);
+       }
+#endif
+}
+
+
+static void op_amd_stop(struct op_msrs const * const msrs)
+{
+       unsigned int low, high;
+       int i;
+
+       /* Subtle: stop on all counters to avoid race with
+        * setting our pm callback */
+       for (i = 0 ; i < NUM_COUNTERS ; ++i) {
+               if (!reset_value[i])
+                       continue;
+               CTRL_READ(low, high, msrs, i);
+               CTRL_SET_INACTIVE(low);
+               CTRL_WRITE(low, high, msrs, i);
+       }
+
+#ifdef CONFIG_OPROFILE_IBS
+       if (ibs_allowed && ibs_config.fetch_enabled) {
+               low = 0;                /* clear max count and enable */
+               high = 0;
+               wrmsr(MSR_AMD64_IBSFETCHCTL, low, high);
+       }
+
+       if (ibs_allowed && ibs_config.op_enabled) {
+               low = 0;                /* clear max count and enable */
+               high = 0;
+               wrmsr(MSR_AMD64_IBSOPCTL, low, high);
+       }
+#endif
+}
+
+static void op_amd_shutdown(struct op_msrs const * const msrs)
+{
+       int i;
+
+       for (i = 0 ; i < NUM_COUNTERS ; ++i) {
+               if (CTR_IS_RESERVED(msrs, i))
+                       release_perfctr_nmi(MSR_K7_PERFCTR0 + i);
+       }
+       for (i = 0 ; i < NUM_CONTROLS ; ++i) {
+               if (CTRL_IS_RESERVED(msrs, i))
+                       release_evntsel_nmi(MSR_K7_EVNTSEL0 + i);
+       }
+}
+
+#ifndef CONFIG_OPROFILE_IBS
+
+/* no IBS support */
+
+static int op_amd_init(struct oprofile_operations *ops)
+{
+       return 0;
+}
+
+static void op_amd_exit(void) {}
+
+#else
+
+static u8 ibs_eilvt_off;
+
+static inline void apic_init_ibs_nmi_per_cpu(void *arg)
+{
+       ibs_eilvt_off = setup_APIC_eilvt_ibs(0, APIC_EILVT_MSG_NMI, 0);
+}
+
+static inline void apic_clear_ibs_nmi_per_cpu(void *arg)
+{
+       setup_APIC_eilvt_ibs(0, APIC_EILVT_MSG_FIX, 1);
+}
+
+static int pfm_amd64_setup_eilvt(void)
+{
+#define IBSCTL_LVTOFFSETVAL            (1 << 8)
+#define IBSCTL                         0x1cc
+       struct pci_dev *cpu_cfg;
+       int nodes;
+       u32 value = 0;
+
+       /* per CPU setup */
+       on_each_cpu(apic_init_ibs_nmi_per_cpu, NULL, 1);
+
+       nodes = 0;
+       cpu_cfg = NULL;
+       do {
+               cpu_cfg = pci_get_device(PCI_VENDOR_ID_AMD,
+                                        PCI_DEVICE_ID_AMD_10H_NB_MISC,
+                                        cpu_cfg);
+               if (!cpu_cfg)
+                       break;
+               ++nodes;
+               pci_write_config_dword(cpu_cfg, IBSCTL, ibs_eilvt_off
+                                      | IBSCTL_LVTOFFSETVAL);
+               pci_read_config_dword(cpu_cfg, IBSCTL, &value);
+               if (value != (ibs_eilvt_off | IBSCTL_LVTOFFSETVAL)) {
+                       printk(KERN_DEBUG "Failed to setup IBS LVT offset, "
+                               "IBSCTL = 0x%08x", value);
+                       return 1;
+               }
+       } while (1);
+
+       if (!nodes) {
+               printk(KERN_DEBUG "No CPU node configured for IBS");
+               return 1;
+       }
+
+#ifdef CONFIG_NUMA
+       /* Sanity check */
+       /* Works only for 64bit with proper numa implementation. */
+       if (nodes != num_possible_nodes()) {
+               printk(KERN_DEBUG "Failed to setup CPU node(s) for IBS, "
+                       "found: %d, expected %d",
+                       nodes, num_possible_nodes());
+               return 1;
+       }
+#endif
+       return 0;
+}
+
+/*
+ * initialize the APIC for the IBS interrupts
+ * if available (AMD Family10h rev B0 and later)
+ */
+static void setup_ibs(void)
+{
+       ibs_allowed = boot_cpu_has(X86_FEATURE_IBS);
+
+       if (!ibs_allowed)
+               return;
+
+       if (pfm_amd64_setup_eilvt()) {
+               ibs_allowed = 0;
+               return;
+       }
+
+       printk(KERN_INFO "oprofile: AMD IBS detected\n");
+}
+
+
+/*
+ * unitialize the APIC for the IBS interrupts if needed on AMD Family10h
+ * rev B0 and later */
+static void clear_ibs_nmi(void)
+{
+       if (ibs_allowed)
+               on_each_cpu(apic_clear_ibs_nmi_per_cpu, NULL, 1);
+}
+
+static int (*create_arch_files)(struct super_block * sb, struct dentry * root);
+
+static int setup_ibs_files(struct super_block * sb, struct dentry * root)
+{
+       char buf[12];
+       struct dentry *dir;
+       int ret = 0;
+
+       /* architecture specific files */
+       if (create_arch_files)
+               ret = create_arch_files(sb, root);
+
+       if (ret)
+               return ret;
+
+       if (!ibs_allowed)
+               return ret;
+
+       /* model specific files */
+
+       /* setup some reasonable defaults */
+       ibs_config.max_cnt_fetch = 250000;
+       ibs_config.fetch_enabled = 0;
+       ibs_config.max_cnt_op = 250000;
+       ibs_config.op_enabled = 0;
+       ibs_config.dispatched_ops = 1;
+       snprintf(buf,  sizeof(buf), "ibs_fetch");
+       dir = oprofilefs_mkdir(sb, root, buf);
+       oprofilefs_create_ulong(sb, dir, "rand_enable",
+                               &ibs_config.rand_en);
+       oprofilefs_create_ulong(sb, dir, "enable",
+               &ibs_config.fetch_enabled);
+       oprofilefs_create_ulong(sb, dir, "max_count",
+               &ibs_config.max_cnt_fetch);
+       snprintf(buf,  sizeof(buf), "ibs_uops");
+       dir = oprofilefs_mkdir(sb, root, buf);
+       oprofilefs_create_ulong(sb, dir, "enable",
+               &ibs_config.op_enabled);
+       oprofilefs_create_ulong(sb, dir, "max_count",
+               &ibs_config.max_cnt_op);
+       oprofilefs_create_ulong(sb, dir, "dispatched_ops",
+               &ibs_config.dispatched_ops);
+
+       return 0;
+}
+
+static int op_amd_init(struct oprofile_operations *ops)
+{
+       setup_ibs();
+       create_arch_files = ops->create_files;
+       ops->create_files = setup_ibs_files;
+       return 0;
+}
+
+static void op_amd_exit(void)
+{
+       clear_ibs_nmi();
+}
+
+#endif
+
+struct op_x86_model_spec const op_amd_spec = {
+       .init = op_amd_init,
+       .exit = op_amd_exit,
+       .num_counters = NUM_COUNTERS,
+       .num_controls = NUM_CONTROLS,
+       .fill_in_addresses = &op_amd_fill_in_addresses,
+       .setup_ctrs = &op_amd_setup_ctrs,
+       .check_ctrs = &op_amd_check_ctrs,
+       .start = &op_amd_start,
+       .stop = &op_amd_stop,
+       .shutdown = &op_amd_shutdown
+};
diff --git a/arch/x86/oprofile/op_model_athlon.c b/arch/x86/oprofile/op_model_athlon.c
deleted file mode 100644 (file)
index 3d53487..0000000
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * @file op_model_athlon.h
- * athlon / K7 / K8 / Family 10h model-specific MSR operations
- *
- * @remark Copyright 2002 OProfile authors
- * @remark Read the file COPYING
- *
- * @author John Levon
- * @author Philippe Elie
- * @author Graydon Hoare
- */
-
-#include <linux/oprofile.h>
-#include <asm/ptrace.h>
-#include <asm/msr.h>
-#include <asm/nmi.h>
-
-#include "op_x86_model.h"
-#include "op_counter.h"
-
-#define NUM_COUNTERS 4
-#define NUM_CONTROLS 4
-
-#define CTR_IS_RESERVED(msrs, c) (msrs->counters[(c)].addr ? 1 : 0)
-#define CTR_READ(l, h, msrs, c) do {rdmsr(msrs->counters[(c)].addr, (l), (h)); } while (0)
-#define CTR_WRITE(l, msrs, c) do {wrmsr(msrs->counters[(c)].addr, -(unsigned int)(l), -1); } while (0)
-#define CTR_OVERFLOWED(n) (!((n) & (1U<<31)))
-
-#define CTRL_IS_RESERVED(msrs, c) (msrs->controls[(c)].addr ? 1 : 0)
-#define CTRL_READ(l, h, msrs, c) do {rdmsr(msrs->controls[(c)].addr, (l), (h)); } while (0)
-#define CTRL_WRITE(l, h, msrs, c) do {wrmsr(msrs->controls[(c)].addr, (l), (h)); } while (0)
-#define CTRL_SET_ACTIVE(n) (n |= (1<<22))
-#define CTRL_SET_INACTIVE(n) (n &= ~(1<<22))
-#define CTRL_CLEAR_LO(x) (x &= (1<<21))
-#define CTRL_CLEAR_HI(x) (x &= 0xfffffcf0)
-#define CTRL_SET_ENABLE(val) (val |= 1<<20)
-#define CTRL_SET_USR(val, u) (val |= ((u & 1) << 16))
-#define CTRL_SET_KERN(val, k) (val |= ((k & 1) << 17))
-#define CTRL_SET_UM(val, m) (val |= (m << 8))
-#define CTRL_SET_EVENT_LOW(val, e) (val |= (e & 0xff))
-#define CTRL_SET_EVENT_HIGH(val, e) (val |= ((e >> 8) & 0xf))
-#define CTRL_SET_HOST_ONLY(val, h) (val |= ((h & 1) << 9))
-#define CTRL_SET_GUEST_ONLY(val, h) (val |= ((h & 1) << 8))
-
-static unsigned long reset_value[NUM_COUNTERS];
-
-static void athlon_fill_in_addresses(struct op_msrs * const msrs)
-{
-       int i;
-
-       for (i = 0; i < NUM_COUNTERS; i++) {
-               if (reserve_perfctr_nmi(MSR_K7_PERFCTR0 + i))
-                       msrs->counters[i].addr = MSR_K7_PERFCTR0 + i;
-               else
-                       msrs->counters[i].addr = 0;
-       }
-
-       for (i = 0; i < NUM_CONTROLS; i++) {
-               if (reserve_evntsel_nmi(MSR_K7_EVNTSEL0 + i))
-                       msrs->controls[i].addr = MSR_K7_EVNTSEL0 + i;
-               else
-                       msrs->controls[i].addr = 0;
-       }
-}
-
-
-static void athlon_setup_ctrs(struct op_msrs const * const msrs)
-{
-       unsigned int low, high;
-       int i;
-
-       /* clear all counters */
-       for (i = 0 ; i < NUM_CONTROLS; ++i) {
-               if (unlikely(!CTRL_IS_RESERVED(msrs, i)))
-                       continue;
-               CTRL_READ(low, high, msrs, i);
-               CTRL_CLEAR_LO(low);
-               CTRL_CLEAR_HI(high);
-               CTRL_WRITE(low, high, msrs, i);
-       }
-
-       /* avoid a false detection of ctr overflows in NMI handler */
-       for (i = 0; i < NUM_COUNTERS; ++i) {
-               if (unlikely(!CTR_IS_RESERVED(msrs, i)))
-                       continue;
-               CTR_WRITE(1, msrs, i);
-       }
-
-       /* enable active counters */
-       for (i = 0; i < NUM_COUNTERS; ++i) {
-               if ((counter_config[i].enabled) && (CTR_IS_RESERVED(msrs, i))) {
-                       reset_value[i] = counter_config[i].count;
-
-                       CTR_WRITE(counter_config[i].count, msrs, i);
-
-                       CTRL_READ(low, high, msrs, i);
-                       CTRL_CLEAR_LO(low);
-                       CTRL_CLEAR_HI(high);
-                       CTRL_SET_ENABLE(low);
-                       CTRL_SET_USR(low, counter_config[i].user);
-                       CTRL_SET_KERN(low, counter_config[i].kernel);
-                       CTRL_SET_UM(low, counter_config[i].unit_mask);
-                       CTRL_SET_EVENT_LOW(low, counter_config[i].event);
-                       CTRL_SET_EVENT_HIGH(high, counter_config[i].event);
-                       CTRL_SET_HOST_ONLY(high, 0);
-                       CTRL_SET_GUEST_ONLY(high, 0);
-
-                       CTRL_WRITE(low, high, msrs, i);
-               } else {
-                       reset_value[i] = 0;
-               }
-       }
-}
-
-
-static int athlon_check_ctrs(struct pt_regs * const regs,
-                            struct op_msrs const * const msrs)
-{
-       unsigned int low, high;
-       int i;
-
-       for (i = 0 ; i < NUM_COUNTERS; ++i) {
-               if (!reset_value[i])
-                       continue;
-               CTR_READ(low, high, msrs, i);
-               if (CTR_OVERFLOWED(low)) {
-                       oprofile_add_sample(regs, i);
-                       CTR_WRITE(reset_value[i], msrs, i);
-               }
-       }
-
-       /* See op_model_ppro.c */
-       return 1;
-}
-
-
-static void athlon_start(struct op_msrs const * const msrs)
-{
-       unsigned int low, high;
-       int i;
-       for (i = 0 ; i < NUM_COUNTERS ; ++i) {
-               if (reset_value[i]) {
-                       CTRL_READ(low, high, msrs, i);
-                       CTRL_SET_ACTIVE(low);
-                       CTRL_WRITE(low, high, msrs, i);
-               }
-       }
-}
-
-
-static void athlon_stop(struct op_msrs const * const msrs)
-{
-       unsigned int low, high;
-       int i;
-
-       /* Subtle: stop on all counters to avoid race with
-        * setting our pm callback */
-       for (i = 0 ; i < NUM_COUNTERS ; ++i) {
-               if (!reset_value[i])
-                       continue;
-               CTRL_READ(low, high, msrs, i);
-               CTRL_SET_INACTIVE(low);
-               CTRL_WRITE(low, high, msrs, i);
-       }
-}
-
-static void athlon_shutdown(struct op_msrs const * const msrs)
-{
-       int i;
-
-       for (i = 0 ; i < NUM_COUNTERS ; ++i) {
-               if (CTR_IS_RESERVED(msrs, i))
-                       release_perfctr_nmi(MSR_K7_PERFCTR0 + i);
-       }
-       for (i = 0 ; i < NUM_CONTROLS ; ++i) {
-               if (CTRL_IS_RESERVED(msrs, i))
-                       release_evntsel_nmi(MSR_K7_EVNTSEL0 + i);
-       }
-}
-
-struct op_x86_model_spec const op_athlon_spec = {
-       .num_counters = NUM_COUNTERS,
-       .num_controls = NUM_CONTROLS,
-       .fill_in_addresses = &athlon_fill_in_addresses,
-       .setup_ctrs = &athlon_setup_ctrs,
-       .check_ctrs = &athlon_check_ctrs,
-       .start = &athlon_start,
-       .stop = &athlon_stop,
-       .shutdown = &athlon_shutdown
-};
index 45b605fa71d06f6064b7fb6f3d34a017106b3cb9..05a0261ba0c38208f4481d467ffc9efc70e57479 100644 (file)
@@ -32,6 +32,8 @@ struct pt_regs;
  * various x86 CPU models' perfctr support.
  */
 struct op_x86_model_spec {
+       int (*init)(struct oprofile_operations *ops);
+       void (*exit)(void);
        unsigned int const num_counters;
        unsigned int const num_controls;
        void (*fill_in_addresses)(struct op_msrs * const msrs);
@@ -46,6 +48,6 @@ struct op_x86_model_spec {
 extern struct op_x86_model_spec const op_ppro_spec;
 extern struct op_x86_model_spec const op_p4_spec;
 extern struct op_x86_model_spec const op_p4_ht2_spec;
-extern struct op_x86_model_spec const op_athlon_spec;
+extern struct op_x86_model_spec const op_amd_spec;
 
 #endif /* OP_X86_MODEL_H */
index 4bdaa590375dd302bac474145f6614924a7a6387..3c27a809393b59051aaa794ad33b2310fd70402c 100644 (file)
@@ -511,3 +511,31 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1201, fam10h_pci_cfg_space_size);
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1202, fam10h_pci_cfg_space_size);
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1203, fam10h_pci_cfg_space_size);
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1204, fam10h_pci_cfg_space_size);
+
+/*
+ * SB600: Disable BAR1 on device 14.0 to avoid HPET resources from
+ * confusing the PCI engine:
+ */
+static void sb600_disable_hpet_bar(struct pci_dev *dev)
+{
+       u8 val;
+
+       /*
+        * The SB600 and SB700 both share the same device
+        * ID, but the PM register 0x55 does something different
+        * for the SB700, so make sure we are dealing with the
+        * SB600 before touching the bit:
+        */
+
+       pci_read_config_byte(dev, 0x08, &val);
+
+       if (val < 0x2F) {
+               outb(0x55, 0xCD6);
+               val = inb(0xCD7);
+
+               /* Set bit 7 in PM register 0x55 */
+               outb(0x55, 0xCD6);
+               outb(val | 0x80, 0xCD7);
+       }
+}
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_ATI, 0x4385, sb600_disable_hpet_bar);
index 8dfcf77cb71783c892437f5cb20eff417c1ee94e..4426bb552bd90849b8df4e06c1a8e03f2a4af12f 100644 (file)
@@ -484,7 +484,7 @@ static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file * file,
                return -EUNATCH;
 
        default:
-               err = n_tty_ioctl(tty, file, cmd, arg);
+               err = n_tty_ioctl_helper(tty, file, cmd, arg);
                break;
        };
 
index caff85149b9d43897730d8fb9319ca1c36b9ca87..700ff9679457efb2a6efe56604f4994ea11f76ab 100644 (file)
@@ -350,7 +350,7 @@ config STALDRV
 
 config STALLION
        tristate "Stallion EasyIO or EC8/32 support"
-       depends on STALDRV && BROKEN_ON_SMP && (ISA || EISA || PCI)
+       depends on STALDRV && (ISA || EISA || PCI)
        help
          If you have an EasyIO or EasyConnection 8/32 multiport Stallion
          card, then this is for you; say Y.  Make sure to read
@@ -361,7 +361,7 @@ config STALLION
 
 config ISTALLION
        tristate "Stallion EC8/64, ONboard, Brumby support"
-       depends on STALDRV && BROKEN_ON_SMP && (ISA || EISA || PCI)
+       depends on STALDRV && (ISA || EISA || PCI)
        help
          If you have an EasyConnection 8/64, ONboard, Brumby or Stallion
          serial multiport card, say Y here. Make sure to read
index 6850f6da75762169374b44a654679d5681f05a1e..1a4247dccac4dfa4d79c27e69c2e93fbdb41fab7 100644 (file)
@@ -7,7 +7,7 @@
 #
 FONTMAPFILE = cp437.uni
 
-obj-y   += mem.o random.o tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o 
+obj-y   += mem.o random.o tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o tty_buffer.o tty_port.o
 
 obj-$(CONFIG_LEGACY_PTYS)      += pty.o
 obj-$(CONFIG_UNIX98_PTYS)      += pty.o
index 6e763e3f5a815565d57e06ab26641c4a6979856d..98821f97583c680b9ddc222d8c15e9909c0feb6b 100644 (file)
@@ -837,9 +837,6 @@ static int rs_put_char(struct tty_struct *tty, unsigned char ch)
        struct async_struct *info;
        unsigned long flags;
 
-       if (!tty)
-               return 0;
-
        info = tty->driver_data;
 
        if (serial_paranoia_check(info, tty->name, "rs_put_char"))
@@ -892,9 +889,6 @@ static int rs_write(struct tty_struct * tty, const unsigned char *buf, int count
        struct async_struct *info;
        unsigned long flags;
 
-       if (!tty)
-               return 0;
-
        info = tty->driver_data;
 
        if (serial_paranoia_check(info, tty->name, "rs_write"))
index 31d08b641f5be84667c5d53e49c862915e65d0c8..b899d9182c7dec0b0b03e2857b680a30806cf12e 100644 (file)
@@ -712,8 +712,7 @@ static int ac_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
        
        IndexCard = adgl->num_card-1;
         
-       if(cmd != 0 && cmd != 6 &&
-          ((IndexCard >= MAX_BOARD) || !apbs[IndexCard].RamIO)) {
+       if(cmd != 6 && ((IndexCard >= MAX_BOARD) || !apbs[IndexCard].RamIO)) {
                static int warncount = 10;
                if (warncount) {
                        printk( KERN_WARNING "APPLICOM driver IOCTL, bad board number %d\n",(int)IndexCard+1);
@@ -832,8 +831,7 @@ static int ac_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
                }
                break;
        default:
-               printk(KERN_INFO "APPLICOM driver ioctl, unknown function code %d\n",cmd) ;
-               ret = -EINVAL;
+               ret = -ENOTTY;
                break;
        }
        Dummy = readb(apbs[IndexCard].RamIO + VERS);
index fe6d774fe2e4cbaf6ae0994cab07fccab158acd9..5e5b1dc1a0a72be733ce32b93966113e6cf224c7 100644 (file)
@@ -4993,12 +4993,14 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
                        device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
                card_name = "Cyclom-Y";
 
-               addr0 = pci_iomap(pdev, 0, CyPCI_Yctl);
+               addr0 = ioremap_nocache(pci_resource_start(pdev, 0),
+                               CyPCI_Yctl);
                if (addr0 == NULL) {
                        dev_err(&pdev->dev, "can't remap ctl region\n");
                        goto err_reg;
                }
-               addr2 = pci_iomap(pdev, 2, CyPCI_Ywin);
+               addr2 = ioremap_nocache(pci_resource_start(pdev, 2),
+                               CyPCI_Ywin);
                if (addr2 == NULL) {
                        dev_err(&pdev->dev, "can't remap base region\n");
                        goto err_unmap;
@@ -5013,7 +5015,8 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
        } else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Hi) {
                struct RUNTIME_9060 __iomem *ctl_addr;
 
-               ctl_addr = addr0 = pci_iomap(pdev, 0, CyPCI_Zctl);
+               ctl_addr = addr0 = ioremap_nocache(pci_resource_start(pdev, 0),
+                               CyPCI_Zctl);
                if (addr0 == NULL) {
                        dev_err(&pdev->dev, "can't remap ctl region\n");
                        goto err_reg;
@@ -5026,8 +5029,8 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
 
                mailbox = (u32)readl(&ctl_addr->mail_box_0);
 
-               addr2 = pci_iomap(pdev, 2, mailbox == ZE_V1 ?
-                               CyPCI_Ze_win : CyPCI_Zwin);
+               addr2 = ioremap_nocache(pci_resource_start(pdev, 2),
+                               mailbox == ZE_V1 ? CyPCI_Ze_win : CyPCI_Zwin);
                if (addr2 == NULL) {
                        dev_err(&pdev->dev, "can't remap base region\n");
                        goto err_unmap;
@@ -5159,9 +5162,9 @@ err_null:
        cy_card[card_no].base_addr = NULL;
        free_irq(irq, &cy_card[card_no]);
 err_unmap:
-       pci_iounmap(pdev, addr0);
+       iounmap(addr0);
        if (addr2)
-               pci_iounmap(pdev, addr2);
+               iounmap(addr2);
 err_reg:
        pci_release_regions(pdev);
 err_dis:
@@ -5186,9 +5189,9 @@ static void __devexit cy_pci_remove(struct pci_dev *pdev)
                cy_writew(cinfo->ctl_addr + 0x68,
                                readw(cinfo->ctl_addr + 0x68) & ~0x0900);
 
-       pci_iounmap(pdev, cinfo->base_addr);
+       iounmap(cinfo->base_addr);
        if (cinfo->ctl_addr)
-               pci_iounmap(pdev, cinfo->ctl_addr);
+               iounmap(cinfo->ctl_addr);
        if (cinfo->irq
 #ifndef CONFIG_CYZ_INTR
                && !IS_CYC_Z(*cinfo)
index 456e4ede049f2a0dad2bd0452199461272f1c353..4998b2761e8f6e891b1595a686f1e29f948e9fcc 100644 (file)
@@ -1376,6 +1376,7 @@ static void post_fep_init(unsigned int crd)
                unsigned long flags;
                u16 tseg, rseg;
 
+               tty_port_init(&ch->port);
                ch->brdchan = bc;
                ch->mailbox = gd;
                INIT_WORK(&ch->tqueue, do_softint);
@@ -1510,10 +1511,6 @@ static void post_fep_init(unsigned int crd)
                ch->fepstopca = 0;
 
                ch->close_delay = 50;
-               ch->port.count = 0;
-               ch->port.blocked_open = 0;
-               init_waitqueue_head(&ch->port.open_wait);
-               init_waitqueue_head(&ch->port.close_wait);
 
                spin_unlock_irqrestore(&epca_lock, flags);
        }
index 19d3afb0e50c5854d466bcee013217c0d52c64b3..c6090f84a2e46cf5f7c571bfd511c2c5b609cd57 100644 (file)
@@ -54,8 +54,6 @@ int gs_put_char(struct tty_struct * tty, unsigned char ch)
 
        func_enter (); 
 
-       if (!tty) return 0;
-
        port = tty->driver_data;
 
        if (!port) return 0;
@@ -97,8 +95,6 @@ int gs_write(struct tty_struct * tty,
 
        func_enter ();
 
-       if (!tty) return 0;
-
        port = tty->driver_data;
 
        if (!port) return 0;
@@ -185,7 +181,6 @@ static int gs_real_chars_in_buffer(struct tty_struct *tty)
        struct gs_port *port;
        func_enter ();
 
-       if (!tty) return 0;
        port = tty->driver_data;
 
        if (!port->rd) return 0;
@@ -274,8 +269,6 @@ void gs_flush_buffer(struct tty_struct *tty)
 
        func_enter ();
 
-       if (!tty) return;
-
        port = tty->driver_data;
 
        if (!port) return;
@@ -296,8 +289,6 @@ void gs_flush_chars(struct tty_struct * tty)
 
        func_enter ();
 
-       if (!tty) return;
-
        port = tty->driver_data;
 
        if (!port) return;
@@ -321,8 +312,6 @@ void gs_stop(struct tty_struct * tty)
 
        func_enter ();
 
-       if (!tty) return;
-
        port = tty->driver_data;
 
        if (!port) return;
@@ -341,8 +330,6 @@ void gs_start(struct tty_struct * tty)
 {
        struct gs_port *port;
 
-       if (!tty) return;
-
        port = tty->driver_data;
 
        if (!port) return;
@@ -393,8 +380,6 @@ void gs_hangup(struct tty_struct *tty)
 
        func_enter ();
 
-       if (!tty) return;
-
        port = tty->driver_data;
        tty = port->port.tty;
        if (!tty) 
@@ -426,8 +411,6 @@ int gs_block_til_ready(void *port_, struct file * filp)
 
        tty = port->port.tty;
 
-       if (!tty) return 0;
-
        gs_dprintk (GS_DEBUG_BTR, "Entering gs_block_till_ready.\n"); 
        /*
         * If the device is in the middle of being closed, then block
@@ -523,8 +506,6 @@ void gs_close(struct tty_struct * tty, struct file * filp)
        
        func_enter ();
 
-       if (!tty) return;
-
        port = (struct gs_port *) tty->driver_data;
 
        if (!port) return;
@@ -621,8 +602,6 @@ void gs_set_termios (struct tty_struct * tty,
 
        func_enter();
 
-       if (!tty) return;
-
        port = tty->driver_data;
 
        if (!port) return;
index b3f5dbc6d8807c7a51cf352118bf5ea08e35d635..f3cfb4c761259d5b8f6d331c24ea1108fde307fc 100644 (file)
 
 #define HPET_RANGE_SIZE                1024    /* from HPET spec */
 
+
+/* WARNING -- don't get confused.  These macros are never used
+ * to write the (single) counter, and rarely to read it.
+ * They're badly named; to fix, someday.
+ */
 #if BITS_PER_LONG == 64
 #define        write_counter(V, MC)    writeq(V, MC)
 #define        read_counter(MC)        readq(MC)
@@ -77,7 +82,7 @@ static struct clocksource clocksource_hpet = {
         .rating         = 250,
         .read           = read_hpet,
         .mask           = CLOCKSOURCE_MASK(64),
-        .mult           = 0, /*to be caluclated*/
+       .mult           = 0, /* to be calculated */
         .shift          = 10,
         .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
 };
@@ -86,8 +91,6 @@ static struct clocksource *hpet_clocksource;
 
 /* A lock for concurrent access by app and isr hpet activity. */
 static DEFINE_SPINLOCK(hpet_lock);
-/* A lock for concurrent intermodule access to hpet and isr hpet activity. */
-static DEFINE_SPINLOCK(hpet_task_lock);
 
 #define        HPET_DEV_NAME   (7)
 
@@ -99,7 +102,6 @@ struct hpet_dev {
        unsigned long hd_irqdata;
        wait_queue_head_t hd_waitqueue;
        struct fasync_struct *hd_async_queue;
-       struct hpet_task *hd_task;
        unsigned int hd_flags;
        unsigned int hd_irq;
        unsigned int hd_hdwirq;
@@ -173,11 +175,6 @@ static irqreturn_t hpet_interrupt(int irq, void *data)
                writel(isr, &devp->hd_hpet->hpet_isr);
        spin_unlock(&hpet_lock);
 
-       spin_lock(&hpet_task_lock);
-       if (devp->hd_task)
-               devp->hd_task->ht_func(devp->hd_task->ht_data);
-       spin_unlock(&hpet_task_lock);
-
        wake_up_interruptible(&devp->hd_waitqueue);
 
        kill_fasync(&devp->hd_async_queue, SIGIO, POLL_IN);
@@ -185,6 +182,67 @@ static irqreturn_t hpet_interrupt(int irq, void *data)
        return IRQ_HANDLED;
 }
 
+static void hpet_timer_set_irq(struct hpet_dev *devp)
+{
+       unsigned long v;
+       int irq, gsi;
+       struct hpet_timer __iomem *timer;
+
+       spin_lock_irq(&hpet_lock);
+       if (devp->hd_hdwirq) {
+               spin_unlock_irq(&hpet_lock);
+               return;
+       }
+
+       timer = devp->hd_timer;
+
+       /* we prefer level triggered mode */
+       v = readl(&timer->hpet_config);
+       if (!(v & Tn_INT_TYPE_CNF_MASK)) {
+               v |= Tn_INT_TYPE_CNF_MASK;
+               writel(v, &timer->hpet_config);
+       }
+       spin_unlock_irq(&hpet_lock);
+
+       v = (readq(&timer->hpet_config) & Tn_INT_ROUTE_CAP_MASK) >>
+                                Tn_INT_ROUTE_CAP_SHIFT;
+
+       /*
+        * In PIC mode, skip IRQ0-4, IRQ6-9, IRQ12-15 which is always used by
+        * legacy device. In IO APIC mode, we skip all the legacy IRQS.
+        */
+       if (acpi_irq_model == ACPI_IRQ_MODEL_PIC)
+               v &= ~0xf3df;
+       else
+               v &= ~0xffff;
+
+       for (irq = find_first_bit(&v, HPET_MAX_IRQ); irq < HPET_MAX_IRQ;
+               irq = find_next_bit(&v, HPET_MAX_IRQ, 1 + irq)) {
+
+               if (irq >= NR_IRQS) {
+                       irq = HPET_MAX_IRQ;
+                       break;
+               }
+
+               gsi = acpi_register_gsi(irq, ACPI_LEVEL_SENSITIVE,
+                                       ACPI_ACTIVE_LOW);
+               if (gsi > 0)
+                       break;
+
+               /* FIXME: Setup interrupt source table */
+       }
+
+       if (irq < HPET_MAX_IRQ) {
+               spin_lock_irq(&hpet_lock);
+               v = readl(&timer->hpet_config);
+               v |= irq << Tn_INT_ROUTE_CNF_SHIFT;
+               writel(v, &timer->hpet_config);
+               devp->hd_hdwirq = gsi;
+               spin_unlock_irq(&hpet_lock);
+       }
+       return;
+}
+
 static int hpet_open(struct inode *inode, struct file *file)
 {
        struct hpet_dev *devp;
@@ -199,8 +257,7 @@ static int hpet_open(struct inode *inode, struct file *file)
 
        for (devp = NULL, hpetp = hpets; hpetp && !devp; hpetp = hpetp->hp_next)
                for (i = 0; i < hpetp->hp_ntimer; i++)
-                       if (hpetp->hp_dev[i].hd_flags & HPET_OPEN
-                           || hpetp->hp_dev[i].hd_task)
+                       if (hpetp->hp_dev[i].hd_flags & HPET_OPEN)
                                continue;
                        else {
                                devp = &hpetp->hp_dev[i];
@@ -219,6 +276,8 @@ static int hpet_open(struct inode *inode, struct file *file)
        spin_unlock_irq(&hpet_lock);
        unlock_kernel();
 
+       hpet_timer_set_irq(devp);
+
        return 0;
 }
 
@@ -441,7 +500,11 @@ static int hpet_ioctl_ieon(struct hpet_dev *devp)
        devp->hd_irq = irq;
        t = devp->hd_ireqfreq;
        v = readq(&timer->hpet_config);
-       g = v | Tn_INT_ENB_CNF_MASK;
+
+       /* 64-bit comparators are not yet supported through the ioctls,
+        * so force this into 32-bit mode if it supports both modes
+        */
+       g = v | Tn_32MODE_CNF_MASK | Tn_INT_ENB_CNF_MASK;
 
        if (devp->hd_flags & HPET_PERIODIC) {
                write_counter(t, &timer->hpet_compare);
@@ -451,6 +514,12 @@ static int hpet_ioctl_ieon(struct hpet_dev *devp)
                v |= Tn_VAL_SET_CNF_MASK;
                writeq(v, &timer->hpet_config);
                local_irq_save(flags);
+
+               /* NOTE:  what we modify here is a hidden accumulator
+                * register supported by periodic-capable comparators.
+                * We never want to modify the (single) counter; that
+                * would affect all the comparators.
+                */
                m = read_counter(&hpet->hpet_mc);
                write_counter(t + m + hpetp->hp_delta, &timer->hpet_compare);
        } else {
@@ -604,57 +673,6 @@ static int hpet_is_known(struct hpet_data *hdp)
        return 0;
 }
 
-static inline int hpet_tpcheck(struct hpet_task *tp)
-{
-       struct hpet_dev *devp;
-       struct hpets *hpetp;
-
-       devp = tp->ht_opaque;
-
-       if (!devp)
-               return -ENXIO;
-
-       for (hpetp = hpets; hpetp; hpetp = hpetp->hp_next)
-               if (devp >= hpetp->hp_dev
-                   && devp < (hpetp->hp_dev + hpetp->hp_ntimer)
-                   && devp->hd_hpet == hpetp->hp_hpet)
-                       return 0;
-
-       return -ENXIO;
-}
-
-#if 0
-int hpet_unregister(struct hpet_task *tp)
-{
-       struct hpet_dev *devp;
-       struct hpet_timer __iomem *timer;
-       int err;
-
-       if ((err = hpet_tpcheck(tp)))
-               return err;
-
-       spin_lock_irq(&hpet_task_lock);
-       spin_lock(&hpet_lock);
-
-       devp = tp->ht_opaque;
-       if (devp->hd_task != tp) {
-               spin_unlock(&hpet_lock);
-               spin_unlock_irq(&hpet_task_lock);
-               return -ENXIO;
-       }
-
-       timer = devp->hd_timer;
-       writeq((readq(&timer->hpet_config) & ~Tn_INT_ENB_CNF_MASK),
-              &timer->hpet_config);
-       devp->hd_flags &= ~(HPET_IE | HPET_PERIODIC);
-       devp->hd_task = NULL;
-       spin_unlock(&hpet_lock);
-       spin_unlock_irq(&hpet_task_lock);
-
-       return 0;
-}
-#endif  /*  0  */
-
 static ctl_table hpet_table[] = {
        {
         .ctl_name = CTL_UNNUMBERED,
@@ -746,6 +764,7 @@ int hpet_alloc(struct hpet_data *hdp)
        static struct hpets *last = NULL;
        unsigned long period;
        unsigned long long temp;
+       u32 remainder;
 
        /*
         * hpet_alloc can be called by platform dependent code.
@@ -809,9 +828,13 @@ int hpet_alloc(struct hpet_data *hdp)
                printk("%s %d", i > 0 ? "," : "", hdp->hd_irq[i]);
        printk("\n");
 
-       printk(KERN_INFO "hpet%u: %u %d-bit timers, %Lu Hz\n",
-              hpetp->hp_which, hpetp->hp_ntimer,
-              cap & HPET_COUNTER_SIZE_MASK ? 64 : 32, hpetp->hp_tick_freq);
+       temp = hpetp->hp_tick_freq;
+       remainder = do_div(temp, 1000000);
+       printk(KERN_INFO
+               "hpet%u: %u comparators, %d-bit %u.%06u MHz counter\n",
+               hpetp->hp_which, hpetp->hp_ntimer,
+               cap & HPET_COUNTER_SIZE_MASK ? 64 : 32,
+               (unsigned) temp, remainder);
 
        mcfg = readq(&hpet->hpet_config);
        if ((mcfg & HPET_ENABLE_CNF_MASK) == 0) {
@@ -874,8 +897,6 @@ static acpi_status hpet_resources(struct acpi_resource *res, void *data)
                hdp->hd_address = ioremap(addr.minimum, addr.address_length);
 
                if (hpet_is_known(hdp)) {
-                       printk(KERN_DEBUG "%s: 0x%lx is busy\n",
-                               __func__, hdp->hd_phys_address);
                        iounmap(hdp->hd_address);
                        return AE_ALREADY_EXISTS;
                }
@@ -891,8 +912,6 @@ static acpi_status hpet_resources(struct acpi_resource *res, void *data)
                                                HPET_RANGE_SIZE);
 
                if (hpet_is_known(hdp)) {
-                       printk(KERN_DEBUG "%s: 0x%lx is busy\n",
-                               __func__, hdp->hd_phys_address);
                        iounmap(hdp->hd_address);
                        return AE_ALREADY_EXISTS;
                }
index fd64137b1ab915fb9384fa674ad54be65c5f0074..ec7aded0a2df9050389cba0d398d6959fdb58162 100644 (file)
@@ -819,11 +819,11 @@ static int hvc_init(void)
        hvc_driver = drv;
        return 0;
 
-put_tty:
-       put_tty_driver(hvc_driver);
 stop_thread:
        kthread_stop(hvc_task);
        hvc_task = NULL;
+put_tty:
+       put_tty_driver(drv);
 out:
        return err;
 }
index 939618f62fe1ba09051c9c16f8056afc975cb76e..bc397d92b499cd6c848d246f8f251aa4aa4670a6 100644 (file)
@@ -4,5 +4,5 @@
 
 obj-$(CONFIG_COMPUTONE)         += ip2.o
 
-ip2-objs                       := ip2base.o ip2main.o
+ip2-objs                       := ip2main.o
 
index 3601017f58cfdd936b490fc69936ab2973a864f5..29db44de399ff37111660a6a506875d89df1b827 100644 (file)
@@ -68,38 +68,6 @@ static DEFINE_RWLOCK(Dl_spinlock);
 // iiInitialize
 //=======================================================
 
-//******************************************************************************
-// Function:   iiEllisInit()
-// Parameters: None
-//
-// Returns:    Nothing
-//
-// Description:
-//
-// This routine performs any required initialization of the iiEllis subsystem.
-//
-//******************************************************************************
-static void
-iiEllisInit(void)
-{
-}
-
-//******************************************************************************
-// Function:   iiEllisCleanup()
-// Parameters: None
-//
-// Returns:    Nothing
-//
-// Description:
-//
-// This routine performs any required cleanup of the iiEllis subsystem.
-//
-//******************************************************************************
-static void
-iiEllisCleanup(void)
-{
-}
-
 //******************************************************************************
 // Function:   iiSetAddress(pB, address, delay)
 // Parameters: pB      - pointer to the board structure
index c88a64e527aa510012e249f1037ae853186b0dbc..fb6df2456018a2238393f40b4cc88b6e78868102 100644 (file)
@@ -511,7 +511,6 @@ typedef void (*delayFunc_t)(unsigned int);
 //
 // Initialization of a board & structure is in four (five!) parts:
 //
-// 0) iiEllisInit()  - Initialize iiEllis subsystem.
 // 1) iiSetAddress() - Define the board address & delay function for a board.
 // 2) iiReset()      - Reset the board   (provided it exists)
 //       -- Note you may do this to several boards --
@@ -523,7 +522,6 @@ typedef void (*delayFunc_t)(unsigned int);
 // loadware.  To change loadware, you must begin again with step 2, resetting
 // the board again (step 1 not needed).
 
-static void iiEllisInit(void);
 static int iiSetAddress(i2eBordStrPtr, int, delayFunc_t );
 static int iiReset(i2eBordStrPtr);
 static int iiResetDelay(i2eBordStrPtr);
diff --git a/drivers/char/ip2/ip2base.c b/drivers/char/ip2/ip2base.c
deleted file mode 100644 (file)
index 8155e24..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-// ip2.c
-// This is a dummy module to make the firmware available when needed
-// and allows it to be unloaded when not. Rumor is the __initdata 
-// macro doesn't always works on all platforms so we use this kludge.
-// If not compiled as a module it just makes fip_firm avaliable then
-//  __initdata should work as advertized
-//
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/wait.h>
-
-#ifndef __init
-#define __init
-#endif
-#ifndef __initfunc
-#define __initfunc(a) a
-#endif
-#ifndef __initdata
-#define __initdata
-#endif
-
-#include "ip2types.h"          
-
-int
-ip2_loadmain(int *, int *); // ref into ip2main.c
-
-/* Note: Add compiled in defaults to these arrays, not to the structure
-       in ip2.h any longer.  That structure WILL get overridden
-       by these values, or command line values, or insmod values!!!  =mhw=
-*/
-static int io[IP2_MAX_BOARDS]= { 0, 0, 0, 0 };
-static int irq[IP2_MAX_BOARDS] = { -1, -1, -1, -1 }; 
-
-static int poll_only = 0;
-
-MODULE_AUTHOR("Doug McNash");
-MODULE_DESCRIPTION("Computone IntelliPort Plus Driver");
-module_param_array(irq, int, NULL, 0);
-MODULE_PARM_DESC(irq,"Interrupts for IntelliPort Cards");
-module_param_array(io, int, NULL, 0);
-MODULE_PARM_DESC(io,"I/O ports for IntelliPort Cards");
-module_param(poll_only, bool, 0);
-MODULE_PARM_DESC(poll_only,"Do not use card interrupts");
-
-
-static int __init ip2_init(void)
-{
-       if( poll_only ) {
-               /* Hard lock the interrupts to zero */
-               irq[0] = irq[1] = irq[2] = irq[3] = 0;
-       }
-
-       return ip2_loadmain(io, irq);
-}
-module_init(ip2_init);
-
-MODULE_LICENSE("GPL");
-
-#ifndef MODULE
-/******************************************************************************
- *     ip2_setup:
- *             str: kernel command line string
- *
- *     Can't autoprobe the boards so user must specify configuration on
- *     kernel command line.  Sane people build it modular but the others
- *     come here.
- *
- *     Alternating pairs of io,irq for up to 4 boards.
- *             ip2=io0,irq0,io1,irq1,io2,irq2,io3,irq3
- *
- *             io=0 => No board
- *             io=1 => PCI
- *             io=2 => EISA
- *             else => ISA I/O address
- *
- *             irq=0 or invalid for ISA will revert to polling mode
- *
- *             Any value = -1, do not overwrite compiled in value.
- *
- ******************************************************************************/
-static int __init ip2_setup(char *str)
-{
-       int     ints[10];       /* 4 boards, 2 parameters + 2 */
-       int     i, j;
-
-       str = get_options (str, ARRAY_SIZE(ints), ints);
-
-       for( i = 0, j = 1; i < 4; i++ ) {
-               if( j > ints[0] ) {
-                       break;
-               }
-               if( ints[j] >= 0 ) {
-                       io[i] = ints[j];
-               }
-               j++;
-               if( j > ints[0] ) {
-                       break;
-               }
-               if( ints[j] >= 0 ) {
-                       irq[i] = ints[j];
-               }
-               j++;
-       }
-       return 1;
-}
-__setup("ip2=", ip2_setup);
-#endif /* !MODULE */
index 689f9dcd3b866f1bd6ca9e3a0f707f7b2de9cb39..6774572d3759e19e2c25fca4e623088cf426643a 100644 (file)
@@ -150,15 +150,12 @@ static int ip2_read_proc(char *, char **, off_t, int, int *, void * );
 /*************/
 
 /* String constants to identify ourselves */
-static char *pcName    = "Computone IntelliPort Plus multiport driver";
-static char *pcVersion = "1.2.14";
+static const char pcName[] = "Computone IntelliPort Plus multiport driver";
+static const char pcVersion[] = "1.2.14";
 
 /* String constants for port names */
-static char *pcDriver_name   = "ip2";
-static char *pcIpl              = "ip2ipl";
-
-// cheezy kludge or genius - you decide?
-int ip2_loadmain(int *, int *);
+static const char pcDriver_name[] = "ip2";
+static const char pcIpl[] = "ip2ipl";
 
 /***********************/
 /* Function Prototypes */
@@ -240,8 +237,8 @@ static const struct file_operations ip2_ipl = {
        .open           = ip2_ipl_open,
 }; 
 
-static unsigned long irq_counter = 0;
-static unsigned long bh_counter = 0;
+static unsigned long irq_counter;
+static unsigned long bh_counter;
 
 // Use immediate queue to service interrupts
 #define USE_IQI
@@ -252,7 +249,6 @@ static unsigned long bh_counter = 0;
  */
 #define  POLL_TIMEOUT   (jiffies + 1)
 static DEFINE_TIMER(PollTimer, ip2_poll, 0, 0);
-static char  TimerOn;
 
 #ifdef IP2DEBUG_TRACE
 /* Trace (debug) buffer data */
@@ -268,8 +264,8 @@ static int tracewrap;
 /**********/
 
 #if defined(MODULE) && defined(IP2DEBUG_OPEN)
-#define DBG_CNT(s) printk(KERN_DEBUG "(%s): [%x] refc=%d, ttyc=%d, modc=%x -> %s\n", \
-                   tty->name,(pCh->flags),ip2_tty_driver->refcount, \
+#define DBG_CNT(s) printk(KERN_DEBUG "(%s): [%x] ttyc=%d, modc=%x -> %s\n", \
+                   tty->name,(pCh->flags), \
                    tty->count,/*GET_USE_COUNT(module)*/0,s)
 #else
 #define DBG_CNT(s)
@@ -287,8 +283,9 @@ static int tracewrap;
 
 MODULE_AUTHOR("Doug McNash");
 MODULE_DESCRIPTION("Computone IntelliPort Plus Driver");
+MODULE_LICENSE("GPL");
 
-static int poll_only = 0;
+static int poll_only;
 
 static int Eisa_irq;
 static int Eisa_slot;
@@ -297,34 +294,46 @@ static int iindx;
 static char rirqs[IP2_MAX_BOARDS];
 static int Valid_Irqs[] = { 3, 4, 5, 7, 10, 11, 12, 15, 0};
 
+/* Note: Add compiled in defaults to these arrays, not to the structure
+       in ip2.h any longer.  That structure WILL get overridden
+       by these values, or command line values, or insmod values!!!  =mhw=
+*/
+static int io[IP2_MAX_BOARDS];
+static int irq[IP2_MAX_BOARDS] = { -1, -1, -1, -1 };
+
+MODULE_AUTHOR("Doug McNash");
+MODULE_DESCRIPTION("Computone IntelliPort Plus Driver");
+module_param_array(irq, int, NULL, 0);
+MODULE_PARM_DESC(irq, "Interrupts for IntelliPort Cards");
+module_param_array(io, int, NULL, 0);
+MODULE_PARM_DESC(io, "I/O ports for IntelliPort Cards");
+module_param(poll_only, bool, 0);
+MODULE_PARM_DESC(poll_only, "Do not use card interrupts");
+
 /* for sysfs class support */
 static struct class *ip2_class;
 
-// Some functions to keep track of what irq's we have
+/* Some functions to keep track of what irqs we have */
 
-static int
-is_valid_irq(int irq)
+static int __init is_valid_irq(int irq)
 {
        int *i = Valid_Irqs;
        
-       while ((*i != 0) && (*i != irq)) {
+       while (*i != 0 && *i != irq)
                i++;
-       }
-       return (*i);
+
+       return *i;
 }
 
-static void
-mark_requested_irq( char irq )
+static void __init mark_requested_irq(char irq)
 {
        rirqs[iindx++] = irq;
 }
 
-#ifdef MODULE
-static int
-clear_requested_irq( char irq )
+static int __exit clear_requested_irq(char irq)
 {
        int i;
-       for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
+       for (i = 0; i < IP2_MAX_BOARDS; ++i) {
                if (rirqs[i] == irq) {
                        rirqs[i] = 0;
                        return 1;
@@ -332,17 +341,15 @@ clear_requested_irq( char irq )
        }
        return 0;
 }
-#endif
 
-static int
-have_requested_irq( char irq )
+static int have_requested_irq(char irq)
 {
-       // array init to zeros so 0 irq will not be requested as a side effect
+       /* array init to zeros so 0 irq will not be requested as a side
+        * effect */
        int i;
-       for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
+       for (i = 0; i < IP2_MAX_BOARDS; ++i)
                if (rirqs[i] == irq)
                        return 1;
-       }
        return 0;
 }
 
@@ -361,53 +368,45 @@ have_requested_irq( char irq )
 /* handle subsequent installations of the driver. All memory allocated by the */
 /* driver should be returned since it may be unloaded from memory.            */
 /******************************************************************************/
-#ifdef MODULE
-void __exit
-ip2_cleanup_module(void)
+static void __exit ip2_cleanup_module(void)
 {
        int err;
        int i;
 
-#ifdef IP2DEBUG_INIT
-       printk (KERN_DEBUG "Unloading %s: version %s\n", pcName, pcVersion );
-#endif
-       /* Stop poll timer if we had one. */
-       if ( TimerOn ) {
-               del_timer ( &PollTimer );
-               TimerOn = 0;
-       }
+       del_timer_sync(&PollTimer);
 
        /* Reset the boards we have. */
-       for( i = 0; i < IP2_MAX_BOARDS; ++i ) {
-               if ( i2BoardPtrTable[i] ) {
-                       iiReset( i2BoardPtrTable[i] );
-               }
-       }
+       for (i = 0; i < IP2_MAX_BOARDS; i++)
+               if (i2BoardPtrTable[i])
+                       iiReset(i2BoardPtrTable[i]);
 
        /* The following is done at most once, if any boards were installed. */
-       for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
-               if ( i2BoardPtrTable[i] ) {
-                       iiResetDelay( i2BoardPtrTable[i] );
+       for (i = 0; i < IP2_MAX_BOARDS; i++) {
+               if (i2BoardPtrTable[i]) {
+                       iiResetDelay(i2BoardPtrTable[i]);
                        /* free io addresses and Tibet */
-                       release_region( ip2config.addr[i], 8 );
+                       release_region(ip2config.addr[i], 8);
                        device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i));
-                       device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i + 1));
+                       device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR,
+                                               4 * i + 1));
                }
                /* Disable and remove interrupt handler. */
-               if ( (ip2config.irq[i] > 0) && have_requested_irq(ip2config.irq[i]) ) { 
-                       free_irq ( ip2config.irq[i], (void *)&pcName);
-                       clear_requested_irq( ip2config.irq[i]);
+               if (ip2config.irq[i] > 0 &&
+                               have_requested_irq(ip2config.irq[i])) {
+                       free_irq(ip2config.irq[i], (void *)&pcName);
+                       clear_requested_irq(ip2config.irq[i]);
                }
        }
        class_destroy(ip2_class);
-       if ( ( err = tty_unregister_driver ( ip2_tty_driver ) ) ) {
-               printk(KERN_ERR "IP2: failed to unregister tty driver (%d)\n", err);
-       }
+       err = tty_unregister_driver(ip2_tty_driver);
+       if (err)
+               printk(KERN_ERR "IP2: failed to unregister tty driver (%d)\n",
+                               err);
        put_tty_driver(ip2_tty_driver);
        unregister_chrdev(IP2_IPL_MAJOR, pcIpl);
        remove_proc_entry("ip2mem", NULL);
 
-       // free memory
+       /* free memory */
        for (i = 0; i < IP2_MAX_BOARDS; i++) {
                void *pB;
 #ifdef CONFIG_PCI
@@ -417,24 +416,18 @@ ip2_cleanup_module(void)
                        ip2config.pci_dev[i] = NULL;
                }
 #endif
-               if ((pB = i2BoardPtrTable[i]) != 0 ) {
-                       kfree ( pB );
+               pB = i2BoardPtrTable[i];
+               if (pB != NULL) {
+                       kfree(pB);
                        i2BoardPtrTable[i] = NULL;
                }
-               if ((DevTableMem[i]) != NULL ) {
-                       kfree ( DevTableMem[i]  );
+               if (DevTableMem[i] != NULL) {
+                       kfree(DevTableMem[i]);
                        DevTableMem[i] = NULL;
                }
        }
-
-       /* Cleanup the iiEllis subsystem. */
-       iiEllisCleanup();
-#ifdef IP2DEBUG_INIT
-       printk (KERN_DEBUG "IP2 Unloaded\n" );
-#endif
 }
 module_exit(ip2_cleanup_module);
-#endif /* MODULE */
 
 static const struct tty_operations ip2_ops = {
        .open            = ip2_open,
@@ -494,139 +487,168 @@ static const struct firmware *ip2_request_firmware(void)
        return fw;
 }
 
-int
-ip2_loadmain(int *iop, int *irqp)
+#ifndef MODULE
+/******************************************************************************
+ *     ip2_setup:
+ *             str: kernel command line string
+ *
+ *     Can't autoprobe the boards so user must specify configuration on
+ *     kernel command line.  Sane people build it modular but the others
+ *     come here.
+ *
+ *     Alternating pairs of io,irq for up to 4 boards.
+ *             ip2=io0,irq0,io1,irq1,io2,irq2,io3,irq3
+ *
+ *             io=0 => No board
+ *             io=1 => PCI
+ *             io=2 => EISA
+ *             else => ISA I/O address
+ *
+ *             irq=0 or invalid for ISA will revert to polling mode
+ *
+ *             Any value = -1, do not overwrite compiled in value.
+ *
+ ******************************************************************************/
+static int __init ip2_setup(char *str)
+{
+       int j, ints[10];        /* 4 boards, 2 parameters + 2 */
+       unsigned int i;
+
+       str = get_options(str, ARRAY_SIZE(ints), ints);
+
+       for (i = 0, j = 1; i < 4; i++) {
+               if (j > ints[0])
+                       break;
+               if (ints[j] >= 0)
+                       io[i] = ints[j];
+               j++;
+               if (j > ints[0])
+                       break;
+               if (ints[j] >= 0)
+                       irq[i] = ints[j];
+               j++;
+       }
+       return 1;
+}
+__setup("ip2=", ip2_setup);
+#endif /* !MODULE */
+
+static int __init ip2_loadmain(void)
 {
        int i, j, box;
        int err = 0;
-       static int loaded;
        i2eBordStrPtr pB = NULL;
        int rc = -1;
-       static struct pci_dev *pci_dev_i = NULL;
+       struct pci_dev *pdev = NULL;
        const struct firmware *fw = NULL;
 
-       ip2trace (ITRC_NO_PORT, ITRC_INIT, ITRC_ENTER, 0 );
+       if (poll_only) {
+               /* Hard lock the interrupts to zero */
+               irq[0] = irq[1] = irq[2] = irq[3] = poll_only = 0;
+       }
+
+       ip2trace(ITRC_NO_PORT, ITRC_INIT, ITRC_ENTER, 0);
 
        /* process command line arguments to modprobe or
                insmod i.e. iop & irqp */
        /* irqp and iop should ALWAYS be specified now...  But we check
                them individually just to be sure, anyways... */
-       for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
-               if (iop) {
-                       ip2config.addr[i] = iop[i];
-                       if (irqp) {
-                               if( irqp[i] >= 0 ) {
-                                       ip2config.irq[i] = irqp[i];
-                               } else {
-                                       ip2config.irq[i] = 0;
-                               }
-       // This is a little bit of a hack.  If poll_only=1 on command
-       // line back in ip2.c OR all IRQs on all specified boards are
-       // explicitly set to 0, then drop to poll only mode and override
-       // PCI or EISA interrupts.  This superceeds the old hack of
-       // triggering if all interrupts were zero (like da default).
-       // Still a hack but less prone to random acts of terrorism.
-       //
-       // What we really should do, now that the IRQ default is set
-       // to -1, is to use 0 as a hard coded, do not probe.
-       //
-       //      /\/\|=mhw=|\/\/
-                               poll_only |= irqp[i];
-                       }
-               }
+       for (i = 0; i < IP2_MAX_BOARDS; ++i) {
+               ip2config.addr[i] = io[i];
+               if (irq[i] >= 0)
+                       ip2config.irq[i] = irq[i];
+               else
+                       ip2config.irq[i] = 0;
+       /* This is a little bit of a hack.  If poll_only=1 on command
+          line back in ip2.c OR all IRQs on all specified boards are
+          explicitly set to 0, then drop to poll only mode and override
+          PCI or EISA interrupts.  This superceeds the old hack of
+          triggering if all interrupts were zero (like da default).
+          Still a hack but less prone to random acts of terrorism.
+
+          What we really should do, now that the IRQ default is set
+          to -1, is to use 0 as a hard coded, do not probe.
+
+               /\/\|=mhw=|\/\/
+       */
+               poll_only |= irq[i];
        }
        poll_only = !poll_only;
 
        /* Announce our presence */
-       printk( KERN_INFO "%s version %s\n", pcName, pcVersion );
-
-       // ip2 can be unloaded and reloaded for no good reason
-       // we can't let that happen here or bad things happen
-       // second load hoses board but not system - fixme later
-       if (loaded) {
-               printk( KERN_INFO "Still loaded\n" );
-               return 0;
-       }
-       loaded++;
+       printk(KERN_INFO "%s version %s\n", pcName, pcVersion);
 
        ip2_tty_driver = alloc_tty_driver(IP2_MAX_PORTS);
        if (!ip2_tty_driver)
                return -ENOMEM;
 
-       /* Initialise the iiEllis subsystem. */
-       iiEllisInit();
-
-       /* Initialize arrays. */
-       memset( i2BoardPtrTable, 0, sizeof i2BoardPtrTable );
-       memset( DevTable, 0, sizeof DevTable );
-
        /* Initialise all the boards we can find (up to the maximum). */
-       for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
-               switch ( ip2config.addr[i] ) { 
+       for (i = 0; i < IP2_MAX_BOARDS; ++i) {
+               switch (ip2config.addr[i]) {
                case 0: /* skip this slot even if card is present */
                        break;
                default: /* ISA */
                   /* ISA address must be specified */
-                       if ( (ip2config.addr[i] < 0x100) || (ip2config.addr[i] > 0x3f8) ) {
-                               printk ( KERN_ERR "IP2: Bad ISA board %d address %x\n",
-                                                        i, ip2config.addr[i] );
+                       if (ip2config.addr[i] < 0x100 ||
+                                       ip2config.addr[i] > 0x3f8) {
+                               printk(KERN_ERR "IP2: Bad ISA board %d "
+                                               "address %x\n", i,
+                                               ip2config.addr[i]);
                                ip2config.addr[i] = 0;
-                       } else {
-                               ip2config.type[i] = ISA;
-
-                               /* Check for valid irq argument, set for polling if invalid */
-                               if (ip2config.irq[i] && !is_valid_irq(ip2config.irq[i])) {
-                                       printk(KERN_ERR "IP2: Bad IRQ(%d) specified\n",ip2config.irq[i]);
-                                       ip2config.irq[i] = 0;// 0 is polling and is valid in that sense
-                               }
+                               break;
+                       }
+                       ip2config.type[i] = ISA;
+
+                       /* Check for valid irq argument, set for polling if
+                        * invalid */
+                       if (ip2config.irq[i] &&
+                                       !is_valid_irq(ip2config.irq[i])) {
+                               printk(KERN_ERR "IP2: Bad IRQ(%d) specified\n",
+                                               ip2config.irq[i]);
+                               /* 0 is polling and is valid in that sense */
+                               ip2config.irq[i] = 0;
                        }
                        break;
                case PCI:
 #ifdef CONFIG_PCI
-                       {
-                               int status;
+               {
+                       u32 addr;
+                       int status;
 
-                               pci_dev_i = pci_get_device(PCI_VENDOR_ID_COMPUTONE,
-                                                         PCI_DEVICE_ID_COMPUTONE_IP2EX, pci_dev_i);
-                               if (pci_dev_i != NULL) {
-                                       unsigned int addr;
-
-                                       if (pci_enable_device(pci_dev_i)) {
-                                               printk( KERN_ERR "IP2: can't enable PCI device at %s\n",
-                                                       pci_name(pci_dev_i));
-                                               break;
-                                       }
-                                       ip2config.type[i] = PCI;
-                                       ip2config.pci_dev[i] = pci_dev_get(pci_dev_i);
-                                       status =
-                                       pci_read_config_dword(pci_dev_i, PCI_BASE_ADDRESS_1, &addr);
-                                       if ( addr & 1 ) {
-                                               ip2config.addr[i]=(USHORT)(addr&0xfffe);
-                                       } else {
-                                               printk( KERN_ERR "IP2: PCI I/O address error\n");
-                                       }
+                       pdev = pci_get_device(PCI_VENDOR_ID_COMPUTONE,
+                                       PCI_DEVICE_ID_COMPUTONE_IP2EX, pdev);
+                       if (pdev == NULL) {
+                               ip2config.addr[i] = 0;
+                               printk(KERN_ERR "IP2: PCI board %d not "
+                                               "found\n", i);
+                               break;
+                       }
 
-//             If the PCI BIOS assigned it, lets try and use it.  If we
-//             can't acquire it or it screws up, deal with it then.
-
-//                                     if (!is_valid_irq(pci_irq)) {
-//                                             printk( KERN_ERR "IP2: Bad PCI BIOS IRQ(%d)\n",pci_irq);
-//                                             pci_irq = 0;
-//                                     }
-                                       ip2config.irq[i] = pci_dev_i->irq;
-                               } else {        // ann error
-                                       ip2config.addr[i] = 0;
-                                       printk(KERN_ERR "IP2: PCI board %d not found\n", i);
-                               } 
+                       if (pci_enable_device(pdev)) {
+                               dev_err(&pdev->dev, "can't enable device\n");
+                               break;
                        }
+                       ip2config.type[i] = PCI;
+                       ip2config.pci_dev[i] = pci_dev_get(pdev);
+                       status = pci_read_config_dword(pdev, PCI_BASE_ADDRESS_1,
+                                       &addr);
+                       if (addr & 1)
+                               ip2config.addr[i] = (USHORT)(addr & 0xfffe);
+                       else
+                               dev_err(&pdev->dev, "I/O address error\n");
+
+                       ip2config.irq[i] = pdev->irq;
+               }
 #else
-                       printk( KERN_ERR "IP2: PCI card specified but PCI support not\n");
-                       printk( KERN_ERR "IP2: configured in this kernel.\n");
-                       printk( KERN_ERR "IP2: Recompile kernel with CONFIG_PCI defined!\n");
+                       printk(KERN_ERR "IP2: PCI card specified but PCI "
+                                       "support not enabled.\n");
+                       printk(KERN_ERR "IP2: Recompile kernel with CONFIG_PCI "
+                                       "defined!\n");
 #endif /* CONFIG_PCI */
                        break;
                case EISA:
-                       if ( (ip2config.addr[i] = find_eisa_board( Eisa_slot + 1 )) != 0) {
+                       ip2config.addr[i] = find_eisa_board(Eisa_slot + 1);
+                       if (ip2config.addr[i] != 0) {
                                /* Eisa_irq set as side effect, boo */
                                ip2config.type[i] = EISA;
                        } 
@@ -634,31 +656,32 @@ ip2_loadmain(int *iop, int *irqp)
                        break;
                }       /* switch */
        }       /* for */
-       if (pci_dev_i)
-               pci_dev_put(pci_dev_i);
+       pci_dev_put(pdev);
 
-       for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
-               if ( ip2config.addr[i] ) {
+       for (i = 0; i < IP2_MAX_BOARDS; ++i) {
+               if (ip2config.addr[i]) {
                        pB = kzalloc(sizeof(i2eBordStr), GFP_KERNEL);
                        if (pB) {
                                i2BoardPtrTable[i] = pB;
-                               iiSetAddress( pB, ip2config.addr[i], ii2DelayTimer );
-                               iiReset( pB );
-                       } else {
-                               printk(KERN_ERR "IP2: board memory allocation error\n");
-                       }
+                               iiSetAddress(pB, ip2config.addr[i],
+                                               ii2DelayTimer);
+                               iiReset(pB);
+                       } else
+                               printk(KERN_ERR "IP2: board memory allocation "
+                                               "error\n");
                }
        }
-       for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
-               if ( ( pB = i2BoardPtrTable[i] ) != NULL ) {
-                       iiResetDelay( pB );
+       for (i = 0; i < IP2_MAX_BOARDS; ++i) {
+               pB = i2BoardPtrTable[i];
+               if (pB != NULL) {
+                       iiResetDelay(pB);
                        break;
                }
        }
-       for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
+       for (i = 0; i < IP2_MAX_BOARDS; ++i) {
                /* We don't want to request the firmware unless we have at
                   least one board */
-               if ( i2BoardPtrTable[i] != NULL ) {
+               if (i2BoardPtrTable[i] != NULL) {
                        if (!fw)
                                fw = ip2_request_firmware();
                        if (!fw)
@@ -669,7 +692,7 @@ ip2_loadmain(int *iop, int *irqp)
        if (fw)
                release_firmware(fw);
 
-       ip2trace (ITRC_NO_PORT, ITRC_INIT, 2, 0 );
+       ip2trace(ITRC_NO_PORT, ITRC_INIT, 2, 0);
 
        ip2_tty_driver->owner               = THIS_MODULE;
        ip2_tty_driver->name                 = "ttyF";
@@ -680,20 +703,23 @@ ip2_loadmain(int *iop, int *irqp)
        ip2_tty_driver->subtype              = SERIAL_TYPE_NORMAL;
        ip2_tty_driver->init_termios         = tty_std_termios;
        ip2_tty_driver->init_termios.c_cflag = B9600|CS8|CREAD|HUPCL|CLOCAL;
-       ip2_tty_driver->flags                = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+       ip2_tty_driver->flags                = TTY_DRIVER_REAL_RAW |
+               TTY_DRIVER_DYNAMIC_DEV;
        tty_set_operations(ip2_tty_driver, &ip2_ops);
 
-       ip2trace (ITRC_NO_PORT, ITRC_INIT, 3, 0 );
+       ip2trace(ITRC_NO_PORT, ITRC_INIT, 3, 0);
 
-       /* Register the tty devices. */
-       if ( ( err = tty_register_driver ( ip2_tty_driver ) ) ) {
-               printk(KERN_ERR "IP2: failed to register tty driver (%d)\n", err);
+       err = tty_register_driver(ip2_tty_driver);
+       if (err) {
+               printk(KERN_ERR "IP2: failed to register tty driver\n");
                put_tty_driver(ip2_tty_driver);
-               return -EINVAL;
-       } else
-       /* Register the IPL driver. */
-       if ( ( err = register_chrdev ( IP2_IPL_MAJOR, pcIpl, &ip2_ipl ) ) ) {
-               printk(KERN_ERR "IP2: failed to register IPL device (%d)\n", err );
+               return err; /* leaking resources */
+       }
+
+       err = register_chrdev(IP2_IPL_MAJOR, pcIpl, &ip2_ipl);
+       if (err) {
+               printk(KERN_ERR "IP2: failed to register IPL device (%d)\n",
+                               err);
        } else {
                /* create the sysfs class */
                ip2_class = class_create(THIS_MODULE, "ip2");
@@ -705,84 +731,86 @@ ip2_loadmain(int *iop, int *irqp)
        /* Register the read_procmem thing */
        if (!proc_create("ip2mem",0,NULL,&ip2mem_proc_fops)) {
                printk(KERN_ERR "IP2: failed to register read_procmem\n");
-       } else {
+               return -EIO; /* leaking resources */
+       }
 
-       ip2trace (ITRC_NO_PORT, ITRC_INIT, 4, 0 );
-               /* Register the interrupt handler or poll handler, depending upon the
-                * specified interrupt.
-                */
+       ip2trace(ITRC_NO_PORT, ITRC_INIT, 4, 0);
+       /* Register the interrupt handler or poll handler, depending upon the
+        * specified interrupt.
+        */
 
-               for( i = 0; i < IP2_MAX_BOARDS; ++i ) {
-                       if ( 0 == ip2config.addr[i] ) {
-                               continue;
-                       }
+       for (i = 0; i < IP2_MAX_BOARDS; ++i) {
+               if (ip2config.addr[i] == 0)
+                       continue;
 
-                       if ( NULL != ( pB = i2BoardPtrTable[i] ) ) {
-                               device_create_drvdata(ip2_class, NULL,
-                                                     MKDEV(IP2_IPL_MAJOR, 4 * i),
-                                                     NULL, "ipl%d", i);
-                               device_create_drvdata(ip2_class, NULL,
-                                                     MKDEV(IP2_IPL_MAJOR, 4 * i + 1),
-                                                     NULL, "stat%d", i);
-
-                           for ( box = 0; box < ABS_MAX_BOXES; ++box )
-                           {
-                               for ( j = 0; j < ABS_BIGGEST_BOX; ++j )
-                               {
-                                   if ( pB->i2eChannelMap[box] & (1 << j) )
-                                   {
-                                       tty_register_device(ip2_tty_driver,
-                                           j + ABS_BIGGEST_BOX *
-                                                   (box+i*ABS_MAX_BOXES), NULL);
-                                   }
-                               }
-                           }
-                       }
+               pB = i2BoardPtrTable[i];
+               if (pB != NULL) {
+                       device_create_drvdata(ip2_class, NULL,
+                                             MKDEV(IP2_IPL_MAJOR, 4 * i),
+                                             NULL, "ipl%d", i);
+                       device_create_drvdata(ip2_class, NULL,
+                                             MKDEV(IP2_IPL_MAJOR, 4 * i + 1),
+                                             NULL, "stat%d", i);
+
+                       for (box = 0; box < ABS_MAX_BOXES; box++)
+                               for (j = 0; j < ABS_BIGGEST_BOX; j++)
+                                       if (pB->i2eChannelMap[box] & (1 << j))
+                                               tty_register_device(
+                                                       ip2_tty_driver,
+                                                       j + ABS_BIGGEST_BOX *
+                                                       (box+i*ABS_MAX_BOXES),
+                                                       NULL);
+               }
 
-                       if (poll_only) {
-//             Poll only forces driver to only use polling and
-//             to ignore the probed PCI or EISA interrupts.
-                               ip2config.irq[i] = CIR_POLL;
-                       }
-                       if ( ip2config.irq[i] == CIR_POLL ) {
+               if (poll_only) {
+                       /* Poll only forces driver to only use polling and
+                          to ignore the probed PCI or EISA interrupts. */
+                       ip2config.irq[i] = CIR_POLL;
+               }
+               if (ip2config.irq[i] == CIR_POLL) {
 retry:
-                               if (!TimerOn) {
-                                       PollTimer.expires = POLL_TIMEOUT;
-                                       add_timer ( &PollTimer );
-                                       TimerOn = 1;
-                                       printk( KERN_INFO "IP2: polling\n");
-                               }
-                       } else {
-                               if (have_requested_irq(ip2config.irq[i]))
-                                       continue;
-                               rc = request_irq( ip2config.irq[i], ip2_interrupt,
-                                       IP2_SA_FLAGS | (ip2config.type[i] == PCI ? IRQF_SHARED : 0),
-                                       pcName, i2BoardPtrTable[i]);
-                               if (rc) {
-                                       printk(KERN_ERR "IP2: an request_irq failed: error %d\n",rc);
-                                       ip2config.irq[i] = CIR_POLL;
-                                       printk( KERN_INFO "IP2: Polling %ld/sec.\n",
-                                                       (POLL_TIMEOUT - jiffies));
-                                       goto retry;
-                               } 
-                               mark_requested_irq(ip2config.irq[i]);
-                               /* Initialise the interrupt handler bottom half (aka slih). */
+                       if (!timer_pending(&PollTimer)) {
+                               mod_timer(&PollTimer, POLL_TIMEOUT);
+                               printk(KERN_INFO "IP2: polling\n");
                        }
-               }
-               for( i = 0; i < IP2_MAX_BOARDS; ++i ) {
-                       if ( i2BoardPtrTable[i] ) {
-                               set_irq( i, ip2config.irq[i] ); /* set and enable board interrupt */
+               } else {
+                       if (have_requested_irq(ip2config.irq[i]))
+                               continue;
+                       rc = request_irq(ip2config.irq[i], ip2_interrupt,
+                               IP2_SA_FLAGS |
+                               (ip2config.type[i] == PCI ? IRQF_SHARED : 0),
+                               pcName, i2BoardPtrTable[i]);
+                       if (rc) {
+                               printk(KERN_ERR "IP2: request_irq failed: "
+                                               "error %d\n", rc);
+                               ip2config.irq[i] = CIR_POLL;
+                               printk(KERN_INFO "IP2: Polling %ld/sec.\n",
+                                               (POLL_TIMEOUT - jiffies));
+                               goto retry;
                        }
+                       mark_requested_irq(ip2config.irq[i]);
+                       /* Initialise the interrupt handler bottom half
+                        * (aka slih). */
                }
        }
-       ip2trace (ITRC_NO_PORT, ITRC_INIT, ITRC_RETURN, 0 );
-       goto out;
+
+       for (i = 0; i < IP2_MAX_BOARDS; ++i) {
+               if (i2BoardPtrTable[i]) {
+                       /* set and enable board interrupt */
+                       set_irq(i, ip2config.irq[i]);
+               }
+       }
+
+       ip2trace(ITRC_NO_PORT, ITRC_INIT, ITRC_RETURN, 0);
+
+       return 0;
 
 out_chrdev:
        unregister_chrdev(IP2_IPL_MAJOR, "ip2");
-out:
+       /* unregister and put tty here */
        return err;
 }
+module_init(ip2_loadmain);
 
 /******************************************************************************/
 /* Function:   ip2_init_board()                                               */
@@ -1199,9 +1227,8 @@ ip2_polled_interrupt(void)
 {
        int i;
        i2eBordStrPtr  pB;
-       const int irq = 0;
 
-       ip2trace (ITRC_NO_PORT, ITRC_INTR, 99, 1, irq );
+       ip2trace(ITRC_NO_PORT, ITRC_INTR, 99, 1, 0);
 
        /* Service just the boards on the list using this irq */
        for( i = 0; i < i2nBoards; ++i ) {
@@ -1210,9 +1237,8 @@ ip2_polled_interrupt(void)
 //             Only process those boards which match our IRQ.
 //                     IRQ = 0 for polled boards, we won't poll "IRQ" boards
 
-               if ( pB && (pB->i2eUsingIrq == irq) ) {
+               if (pB && pB->i2eUsingIrq == 0)
                        ip2_irq_work(pB);
-               }
        }
 
        ++irq_counter;
@@ -1250,16 +1276,12 @@ ip2_poll(unsigned long arg)
 {
        ip2trace (ITRC_NO_PORT, ITRC_INTR, 100, 0 );
 
-       TimerOn = 0; // it's the truth but not checked in service
-
        // Just polled boards, IRQ = 0 will hit all non-interrupt boards.
        // It will NOT poll boards handled by hard interrupts.
        // The issue of queued BH interrupts is handled in ip2_interrupt().
        ip2_polled_interrupt();
 
-       PollTimer.expires = POLL_TIMEOUT;
-       add_timer( &PollTimer );
-       TimerOn = 1;
+       mod_timer(&PollTimer, POLL_TIMEOUT);
 
        ip2trace (ITRC_NO_PORT, ITRC_INTR, ITRC_RETURN, 0 );
 }
@@ -2871,7 +2893,7 @@ ip2_ipl_ioctl (struct file *pFile, UINT cmd, ULONG arg )
        case 13:
                switch ( cmd ) {
                case 64:        /* Driver - ip2stat */
-                       rc = put_user(ip2_tty_driver->refcount, pIndex++ );
+                       rc = put_user(-1, pIndex++ );
                        rc = put_user(irq_counter, pIndex++  );
                        rc = put_user(bh_counter, pIndex++  );
                        break;
index 8f7cc190b62d420116b5c0d30e70899c3332c94d..7d30ee1d3fca9de33cb5e23790fd6df96c791e05 100644 (file)
@@ -421,17 +421,16 @@ static void isicom_tx(unsigned long _data)
        if (retries >= 100)
                goto unlock;
 
+       tty = tty_port_tty_get(&port->port);
+       if (tty == NULL)
+               goto put_unlock;
+
        for (; count > 0; count--, port++) {
                /* port not active or tx disabled to force flow control */
                if (!(port->port.flags & ASYNC_INITIALIZED) ||
                                !(port->status & ISI_TXOK))
                        continue;
 
-               tty = port->port.tty;
-
-               if (tty == NULL)
-                       continue;
-
                txcount = min_t(short, TX_SIZE, port->xmit_cnt);
                if (txcount <= 0 || tty->stopped || tty->hw_stopped)
                        continue;
@@ -489,6 +488,8 @@ static void isicom_tx(unsigned long _data)
                        tty_wakeup(tty);
        }
 
+put_unlock:
+       tty_kref_put(tty);
 unlock:
        spin_unlock_irqrestore(&isi_card[card].card_lock, flags);
        /*      schedule another tx for hopefully in about 10ms */
@@ -547,7 +548,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id)
                return IRQ_HANDLED;
        }
 
-       tty = port->port.tty;
+       tty = tty_port_tty_get(&port->port);
        if (tty == NULL) {
                word_count = byte_count >> 1;
                while (byte_count > 1) {
@@ -588,7 +589,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id)
                        }
 
                        if (port->port.flags & ASYNC_CTS_FLOW) {
-                               if (port->port.tty->hw_stopped) {
+                               if (tty->hw_stopped) {
                                        if (header & ISI_CTS) {
                                                port->port.tty->hw_stopped = 0;
                                                /* start tx ing */
@@ -597,7 +598,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id)
                                                tty_wakeup(tty);
                                        }
                                } else if (!(header & ISI_CTS)) {
-                                       port->port.tty->hw_stopped = 1;
+                                       tty->hw_stopped = 1;
                                        /* stop tx ing */
                                        port->status &= ~(ISI_TXOK | ISI_CTS);
                                }
@@ -660,24 +661,21 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id)
        }
        outw(0x0000, base+0x04); /* enable interrupts */
        spin_unlock(&card->card_lock);
+       tty_kref_put(tty);
 
        return IRQ_HANDLED;
 }
 
-static void isicom_config_port(struct isi_port *port)
+static void isicom_config_port(struct tty_struct *tty)
 {
+       struct isi_port *port = tty->driver_data;
        struct isi_board *card = port->card;
-       struct tty_struct *tty;
        unsigned long baud;
        unsigned long base = card->base;
        u16 channel_setup, channel = port->channel,
                shift_count = card->shift_count;
        unsigned char flow_ctrl;
 
-       tty = port->port.tty;
-
-       if (tty == NULL)
-               return;
        /* FIXME: Switch to new tty baud API */
        baud = C_BAUD(tty);
        if (baud & CBAUDEX) {
@@ -690,7 +688,7 @@ static void isicom_config_port(struct isi_port *port)
 
                /* 1,2,3,4 => 57.6, 115.2, 230, 460 kbps resp. */
                if (baud < 1 || baud > 4)
-                       port->port.tty->termios->c_cflag &= ~CBAUDEX;
+                       tty->termios->c_cflag &= ~CBAUDEX;
                else
                        baud += 15;
        }
@@ -797,8 +795,9 @@ static inline void isicom_setup_board(struct isi_board *bp)
        spin_unlock_irqrestore(&bp->card_lock, flags);
 }
 
-static int isicom_setup_port(struct isi_port *port)
+static int isicom_setup_port(struct tty_struct *tty)
 {
+       struct isi_port *port = tty->driver_data;
        struct isi_board *card = port->card;
        unsigned long flags;
 
@@ -808,8 +807,7 @@ static int isicom_setup_port(struct isi_port *port)
                return -ENOMEM;
 
        spin_lock_irqsave(&card->card_lock, flags);
-       if (port->port.tty)
-               clear_bit(TTY_IO_ERROR, &port->port.tty->flags);
+       clear_bit(TTY_IO_ERROR, &tty->flags);
        if (port->port.count == 1)
                card->count++;
 
@@ -823,7 +821,7 @@ static int isicom_setup_port(struct isi_port *port)
                InterruptTheCard(card->base);
        }
 
-       isicom_config_port(port);
+       isicom_config_port(tty);
        port->port.flags |= ASYNC_INITIALIZED;
        spin_unlock_irqrestore(&card->card_lock, flags);
 
@@ -934,8 +932,8 @@ static int isicom_open(struct tty_struct *tty, struct file *filp)
 
        port->port.count++;
        tty->driver_data = port;
-       port->port.tty = tty;
-       error = isicom_setup_port(port);
+       tty_port_tty_set(&port->port, tty);
+       error = isicom_setup_port(tty);
        if (error == 0)
                error = block_til_ready(tty, filp, port);
        return error;
@@ -955,15 +953,17 @@ static void isicom_shutdown_port(struct isi_port *port)
        struct isi_board *card = port->card;
        struct tty_struct *tty;
 
-       tty = port->port.tty;
+       tty = tty_port_tty_get(&port->port);
 
-       if (!(port->port.flags & ASYNC_INITIALIZED))
+       if (!(port->port.flags & ASYNC_INITIALIZED)) {
+               tty_kref_put(tty);
                return;
+       }
 
        tty_port_free_xmit_buf(&port->port);
        port->port.flags &= ~ASYNC_INITIALIZED;
        /* 3rd October 2000 : Vinayak P Risbud */
-       port->port.tty = NULL;
+       tty_port_tty_set(&port->port, NULL);
 
        /*Fix done by Anil .S on 30-04-2001
        remote login through isi port has dtr toggle problem
@@ -1243,9 +1243,10 @@ static int isicom_tiocmset(struct tty_struct *tty, struct file *file,
        return 0;
 }
 
-static int isicom_set_serial_info(struct isi_port *port,
-       struct serial_struct __user *info)
+static int isicom_set_serial_info(struct tty_struct *tty,
+                                       struct serial_struct __user *info)
 {
+       struct isi_port *port = tty->driver_data;
        struct serial_struct newinfo;
        int reconfig_port;
 
@@ -1276,7 +1277,7 @@ static int isicom_set_serial_info(struct isi_port *port,
        if (reconfig_port) {
                unsigned long flags;
                spin_lock_irqsave(&port->card->card_lock, flags);
-               isicom_config_port(port);
+               isicom_config_port(tty);
                spin_unlock_irqrestore(&port->card->card_lock, flags);
        }
        unlock_kernel();
@@ -1318,7 +1319,7 @@ static int isicom_ioctl(struct tty_struct *tty, struct file *filp,
                return isicom_get_serial_info(port, argp);
 
        case TIOCSSERIAL:
-               return isicom_set_serial_info(port, argp);
+               return isicom_set_serial_info(tty, argp);
 
        default:
                return -ENOIOCTLCMD;
@@ -1341,7 +1342,7 @@ static void isicom_set_termios(struct tty_struct *tty,
                return;
 
        spin_lock_irqsave(&port->card->card_lock, flags);
-       isicom_config_port(port);
+       isicom_config_port(tty);
        spin_unlock_irqrestore(&port->card->card_lock, flags);
 
        if ((old_termios->c_cflag & CRTSCTS) &&
@@ -1419,7 +1420,7 @@ static void isicom_hangup(struct tty_struct *tty)
 
        port->port.count = 0;
        port->port.flags &= ~ASYNC_NORMAL_ACTIVE;
-       port->port.tty = NULL;
+       tty_port_tty_set(&port->port, NULL);
        wake_up_interruptible(&port->port.open_wait);
 }
 
index 843a2afaf2040f2a641af8ea33a4f10b570e5a04..505d7a1f6b8cc39a37c0b9b3e0d04e06f796aba2 100644 (file)
@@ -623,24 +623,25 @@ static int        stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, un
 static void    stli_brdpoll(struct stlibrd *brdp, cdkhdr_t __iomem *hdrp);
 static void    stli_poll(unsigned long arg);
 static int     stli_hostcmd(struct stlibrd *brdp, struct stliport *portp);
-static int     stli_initopen(struct stlibrd *brdp, struct stliport *portp);
+static int     stli_initopen(struct tty_struct *tty, struct stlibrd *brdp, struct stliport *portp);
 static int     stli_rawopen(struct stlibrd *brdp, struct stliport *portp, unsigned long arg, int wait);
 static int     stli_rawclose(struct stlibrd *brdp, struct stliport *portp, unsigned long arg, int wait);
-static int     stli_waitcarrier(struct stlibrd *brdp, struct stliport *portp, struct file *filp);
-static int     stli_setport(struct stliport *portp);
+static int     stli_waitcarrier(struct tty_struct *tty, struct stlibrd *brdp,
+                               struct stliport *portp, struct file *filp);
+static int     stli_setport(struct tty_struct *tty);
 static int     stli_cmdwait(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback);
 static void    stli_sendcmd(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback);
 static void    __stli_sendcmd(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback);
 static void    stli_dodelaycmd(struct stliport *portp, cdkctrl_t __iomem *cp);
-static void    stli_mkasyport(struct stliport *portp, asyport_t *pp, struct ktermios *tiosp);
+static void    stli_mkasyport(struct tty_struct *tty, struct stliport *portp, asyport_t *pp, struct ktermios *tiosp);
 static void    stli_mkasysigs(asysigs_t *sp, int dtr, int rts);
 static long    stli_mktiocm(unsigned long sigvalue);
 static void    stli_read(struct stlibrd *brdp, struct stliport *portp);
 static int     stli_getserial(struct stliport *portp, struct serial_struct __user *sp);
-static int     stli_setserial(struct stliport *portp, struct serial_struct __user *sp);
+static int     stli_setserial(struct tty_struct *tty, struct serial_struct __user *sp);
 static int     stli_getbrdstats(combrd_t __user *bp);
-static int     stli_getportstats(struct stliport *portp, comstats_t __user *cp);
-static int     stli_portcmdstats(struct stliport *portp);
+static int     stli_getportstats(struct tty_struct *tty, struct stliport *portp, comstats_t __user *cp);
+static int     stli_portcmdstats(struct tty_struct *tty, struct stliport *portp);
 static int     stli_clrportstats(struct stliport *portp, comstats_t __user *cp);
 static int     stli_getportstruct(struct stliport __user *arg);
 static int     stli_getbrdstruct(struct stlibrd __user *arg);
@@ -731,12 +732,16 @@ static void stli_cleanup_ports(struct stlibrd *brdp)
 {
        struct stliport *portp;
        unsigned int j;
+       struct tty_struct *tty;
 
        for (j = 0; j < STL_MAXPORTS; j++) {
                portp = brdp->ports[j];
                if (portp != NULL) {
-                       if (portp->port.tty != NULL)
-                               tty_hangup(portp->port.tty);
+                       tty = tty_port_tty_get(&portp->port);
+                       if (tty != NULL) {
+                               tty_hangup(tty);
+                               tty_kref_put(tty);
+                       }
                        kfree(portp);
                }
        }
@@ -824,7 +829,7 @@ static int stli_open(struct tty_struct *tty, struct file *filp)
  *     requires several commands to the board we will need to wait for any
  *     other open that is already initializing the port.
  */
-       portp->port.tty = tty;
+       tty_port_tty_set(&portp->port, tty);
        tty->driver_data = portp;
        portp->port.count++;
 
@@ -835,7 +840,7 @@ static int stli_open(struct tty_struct *tty, struct file *filp)
 
        if ((portp->port.flags & ASYNC_INITIALIZED) == 0) {
                set_bit(ST_INITIALIZING, &portp->state);
-               if ((rc = stli_initopen(brdp, portp)) >= 0) {
+               if ((rc = stli_initopen(tty, brdp, portp)) >= 0) {
                        portp->port.flags |= ASYNC_INITIALIZED;
                        clear_bit(TTY_IO_ERROR, &tty->flags);
                }
@@ -864,7 +869,7 @@ static int stli_open(struct tty_struct *tty, struct file *filp)
  *     then also we might have to wait for carrier.
  */
        if (!(filp->f_flags & O_NONBLOCK)) {
-               if ((rc = stli_waitcarrier(brdp, portp, filp)) != 0)
+               if ((rc = stli_waitcarrier(tty, brdp, portp, filp)) != 0)
                        return rc;
        }
        portp->port.flags |= ASYNC_NORMAL_ACTIVE;
@@ -930,7 +935,7 @@ static void stli_close(struct tty_struct *tty, struct file *filp)
        stli_flushbuffer(tty);
 
        tty->closing = 0;
-       portp->port.tty = NULL;
+       tty_port_tty_set(&portp->port, NULL);
 
        if (portp->openwaitcnt) {
                if (portp->close_delay)
@@ -952,9 +957,9 @@ static void stli_close(struct tty_struct *tty, struct file *filp)
  *     this still all happens pretty quickly.
  */
 
-static int stli_initopen(struct stlibrd *brdp, struct stliport *portp)
+static int stli_initopen(struct tty_struct *tty,
+                               struct stlibrd *brdp, struct stliport *portp)
 {
-       struct tty_struct *tty;
        asynotify_t nt;
        asyport_t aport;
        int rc;
@@ -969,10 +974,7 @@ static int stli_initopen(struct stlibrd *brdp, struct stliport *portp)
            sizeof(asynotify_t), 0)) < 0)
                return rc;
 
-       tty = portp->port.tty;
-       if (tty == NULL)
-               return -ENODEV;
-       stli_mkasyport(portp, &aport, tty->termios);
+       stli_mkasyport(tty, portp, &aport, tty->termios);
        if ((rc = stli_cmdwait(brdp, portp, A_SETPORT, &aport,
            sizeof(asyport_t), 0)) < 0)
                return rc;
@@ -1161,22 +1163,21 @@ static int stli_cmdwait(struct stlibrd *brdp, struct stliport *portp, unsigned l
  *     waiting for the command to complete - so must have user context.
  */
 
-static int stli_setport(struct stliport *portp)
+static int stli_setport(struct tty_struct *tty)
 {
+       struct stliport *portp = tty->driver_data;
        struct stlibrd *brdp;
        asyport_t aport;
 
        if (portp == NULL)
                return -ENODEV;
-       if (portp->port.tty == NULL)
-               return -ENODEV;
        if (portp->brdnr >= stli_nrbrds)
                return -ENODEV;
        brdp = stli_brds[portp->brdnr];
        if (brdp == NULL)
                return -ENODEV;
 
-       stli_mkasyport(portp, &aport, portp->port.tty->termios);
+       stli_mkasyport(tty, portp, &aport, tty->termios);
        return(stli_cmdwait(brdp, portp, A_SETPORT, &aport, sizeof(asyport_t), 0));
 }
 
@@ -1187,7 +1188,8 @@ static int stli_setport(struct stliport *portp)
  *     maybe because if we are clocal then we don't need to wait...
  */
 
-static int stli_waitcarrier(struct stlibrd *brdp, struct stliport *portp, struct file *filp)
+static int stli_waitcarrier(struct tty_struct *tty, struct stlibrd *brdp,
+                               struct stliport *portp, struct file *filp)
 {
        unsigned long flags;
        int rc, doclocal;
@@ -1195,7 +1197,7 @@ static int stli_waitcarrier(struct stlibrd *brdp, struct stliport *portp, struct
        rc = 0;
        doclocal = 0;
 
-       if (portp->port.tty->termios->c_cflag & CLOCAL)
+       if (tty->termios->c_cflag & CLOCAL)
                doclocal++;
 
        spin_lock_irqsave(&stli_lock, flags);
@@ -1373,8 +1375,6 @@ static void stli_flushchars(struct tty_struct *tty)
        stli_txcookrealsize = 0;
        stli_txcooktty = NULL;
 
-       if (tty == NULL)
-               return;
        if (cooktty == NULL)
                return;
        if (tty != cooktty)
@@ -1572,10 +1572,11 @@ static int stli_getserial(struct stliport *portp, struct serial_struct __user *s
  *     just quietly ignore any requests to change irq, etc.
  */
 
-static int stli_setserial(struct stliport *portp, struct serial_struct __user *sp)
+static int stli_setserial(struct tty_struct *tty, struct serial_struct __user *sp)
 {
        struct serial_struct sio;
        int rc;
+       struct stliport *portp = tty->driver_data;
 
        if (copy_from_user(&sio, sp, sizeof(struct serial_struct)))
                return -EFAULT;
@@ -1594,7 +1595,7 @@ static int stli_setserial(struct stliport *portp, struct serial_struct __user *s
        portp->closing_wait = sio.closing_wait;
        portp->custom_divisor = sio.custom_divisor;
 
-       if ((rc = stli_setport(portp)) < 0)
+       if ((rc = stli_setport(tty)) < 0)
                return rc;
        return 0;
 }
@@ -1685,17 +1686,17 @@ static int stli_ioctl(struct tty_struct *tty, struct file *file, unsigned int cm
                rc = stli_getserial(portp, argp);
                break;
        case TIOCSSERIAL:
-               rc = stli_setserial(portp, argp);
+               rc = stli_setserial(tty, argp);
                break;
        case STL_GETPFLAG:
                rc = put_user(portp->pflag, (unsigned __user *)argp);
                break;
        case STL_SETPFLAG:
                if ((rc = get_user(portp->pflag, (unsigned __user *)argp)) == 0)
-                       stli_setport(portp);
+                       stli_setport(tty);
                break;
        case COM_GETPORTSTATS:
-               rc = stli_getportstats(portp, argp);
+               rc = stli_getportstats(tty, portp, argp);
                break;
        case COM_CLRPORTSTATS:
                rc = stli_clrportstats(portp, argp);
@@ -1729,8 +1730,6 @@ static void stli_settermios(struct tty_struct *tty, struct ktermios *old)
        struct ktermios *tiosp;
        asyport_t aport;
 
-       if (tty == NULL)
-               return;
        portp = tty->driver_data;
        if (portp == NULL)
                return;
@@ -1742,7 +1741,7 @@ static void stli_settermios(struct tty_struct *tty, struct ktermios *old)
 
        tiosp = tty->termios;
 
-       stli_mkasyport(portp, &aport, tiosp);
+       stli_mkasyport(tty, portp, &aport, tiosp);
        stli_cmdwait(brdp, portp, A_SETPORT, &aport, sizeof(asyport_t), 0);
        stli_mkasysigs(&portp->asig, ((tiosp->c_cflag & CBAUD) ? 1 : 0), -1);
        stli_cmdwait(brdp, portp, A_SETSIGNALS, &portp->asig,
@@ -1854,7 +1853,7 @@ static void stli_hangup(struct tty_struct *tty)
        clear_bit(ST_TXBUSY, &portp->state);
        clear_bit(ST_RXSTOP, &portp->state);
        set_bit(TTY_IO_ERROR, &tty->flags);
-       portp->port.tty = NULL;
+       tty_port_tty_set(&portp->port, NULL);
        portp->port.flags &= ~ASYNC_NORMAL_ACTIVE;
        portp->port.count = 0;
        spin_unlock_irqrestore(&stli_lock, flags);
@@ -1935,8 +1934,6 @@ static void stli_waituntilsent(struct tty_struct *tty, int timeout)
        struct stliport *portp;
        unsigned long tend;
 
-       if (tty == NULL)
-               return;
        portp = tty->driver_data;
        if (portp == NULL)
                return;
@@ -1998,7 +1995,7 @@ static int stli_portinfo(struct stlibrd *brdp, struct stliport *portp, int portn
        char *sp, *uart;
        int rc, cnt;
 
-       rc = stli_portcmdstats(portp);
+       rc = stli_portcmdstats(NULL, portp);
 
        uart = "UNKNOWN";
        if (brdp->state & BST_STARTED) {
@@ -2188,7 +2185,7 @@ static void stli_read(struct stlibrd *brdp, struct stliport *portp)
 
        if (test_bit(ST_RXSTOP, &portp->state))
                return;
-       tty = portp->port.tty;
+       tty = tty_port_tty_get(&portp->port);
        if (tty == NULL)
                return;
 
@@ -2230,6 +2227,7 @@ static void stli_read(struct stlibrd *brdp, struct stliport *portp)
                set_bit(ST_RXING, &portp->state);
 
        tty_schedule_flip(tty);
+       tty_kref_put(tty);
 }
 
 /*****************************************************************************/
@@ -2362,7 +2360,7 @@ static int stli_hostcmd(struct stlibrd *brdp, struct stliport *portp)
        if (ap->notify) {
                nt = ap->changed;
                ap->notify = 0;
-               tty = portp->port.tty;
+               tty = tty_port_tty_get(&portp->port);
 
                if (nt.signal & SG_DCD) {
                        oldsigs = portp->sigs;
@@ -2399,6 +2397,7 @@ static int stli_hostcmd(struct stlibrd *brdp, struct stliport *portp)
                                tty_schedule_flip(tty);
                        }
                }
+               tty_kref_put(tty);
 
                if (nt.data & DT_RXBUSY) {
                        donerx++;
@@ -2535,14 +2534,15 @@ static void stli_poll(unsigned long arg)
  *     the slave.
  */
 
-static void stli_mkasyport(struct stliport *portp, asyport_t *pp, struct ktermios *tiosp)
+static void stli_mkasyport(struct tty_struct *tty, struct stliport *portp,
+                               asyport_t *pp, struct ktermios *tiosp)
 {
        memset(pp, 0, sizeof(asyport_t));
 
 /*
  *     Start of by setting the baud, char size, parity and stop bit info.
  */
-       pp->baudout = tty_get_baud_rate(portp->port.tty);
+       pp->baudout = tty_get_baud_rate(tty);
        if ((tiosp->c_cflag & CBAUD) == B38400) {
                if ((portp->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
                        pp->baudout = 57600;
@@ -2695,7 +2695,7 @@ static int stli_initports(struct stlibrd *brdp)
                        printk("STALLION: failed to allocate port structure\n");
                        continue;
                }
-
+               tty_port_init(&portp->port);
                portp->magic = STLI_PORTMAGIC;
                portp->portnr = i;
                portp->brdnr = brdp->brdnr;
@@ -4220,7 +4220,7 @@ static struct stliport *stli_getport(unsigned int brdnr, unsigned int panelnr,
  *     what port to get stats for (used through board control device).
  */
 
-static int stli_portcmdstats(struct stliport *portp)
+static int stli_portcmdstats(struct tty_struct *tty, struct stliport *portp)
 {
        unsigned long   flags;
        struct stlibrd  *brdp;
@@ -4249,15 +4249,15 @@ static int stli_portcmdstats(struct stliport *portp)
        stli_comstats.flags = portp->port.flags;
 
        spin_lock_irqsave(&brd_lock, flags);
-       if (portp->port.tty != NULL) {
-               if (portp->port.tty->driver_data == portp) {
-                       stli_comstats.ttystate = portp->port.tty->flags;
+       if (tty != NULL) {
+               if (portp->port.tty == tty) {
+                       stli_comstats.ttystate = tty->flags;
                        stli_comstats.rxbuffered = -1;
-                       if (portp->port.tty->termios != NULL) {
-                               stli_comstats.cflags = portp->port.tty->termios->c_cflag;
-                               stli_comstats.iflags = portp->port.tty->termios->c_iflag;
-                               stli_comstats.oflags = portp->port.tty->termios->c_oflag;
-                               stli_comstats.lflags = portp->port.tty->termios->c_lflag;
+                       if (tty->termios != NULL) {
+                               stli_comstats.cflags = tty->termios->c_cflag;
+                               stli_comstats.iflags = tty->termios->c_iflag;
+                               stli_comstats.oflags = tty->termios->c_oflag;
+                               stli_comstats.lflags = tty->termios->c_lflag;
                        }
                }
        }
@@ -4294,7 +4294,8 @@ static int stli_portcmdstats(struct stliport *portp)
  *     what port to get stats for (used through board control device).
  */
 
-static int stli_getportstats(struct stliport *portp, comstats_t __user *cp)
+static int stli_getportstats(struct tty_struct *tty, struct stliport *portp,
+                                                       comstats_t __user *cp)
 {
        struct stlibrd *brdp;
        int rc;
@@ -4312,7 +4313,7 @@ static int stli_getportstats(struct stliport *portp, comstats_t __user *cp)
        if (!brdp)
                return -ENODEV;
 
-       if ((rc = stli_portcmdstats(portp)) < 0)
+       if ((rc = stli_portcmdstats(tty, portp)) < 0)
                return rc;
 
        return copy_to_user(cp, &stli_comstats, sizeof(comstats_t)) ?
@@ -4427,7 +4428,7 @@ static int stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, un
 
        switch (cmd) {
        case COM_GETPORTSTATS:
-               rc = stli_getportstats(NULL, argp);
+               rc = stli_getportstats(NULL, NULL, argp);
                done++;
                break;
        case COM_CLRPORTSTATS:
index d3d7864e0c1ef566b86d9a5cfb72c45d2aaf5836..5df4003ad8736f0e544dbc685010f7d8da783be1 100644 (file)
@@ -205,7 +205,7 @@ static int moxa_tiocmset(struct tty_struct *tty, struct file *file,
 static void moxa_poll(unsigned long);
 static void moxa_set_tty_param(struct tty_struct *, struct ktermios *);
 static void moxa_setup_empty_event(struct tty_struct *);
-static void moxa_shut_down(struct moxa_port *);
+static void moxa_shut_down(struct tty_struct *);
 /*
  * moxa board interface functions:
  */
@@ -217,7 +217,7 @@ static void MoxaPortLineCtrl(struct moxa_port *, int, int);
 static void MoxaPortFlowCtrl(struct moxa_port *, int, int, int, int, int);
 static int MoxaPortLineStatus(struct moxa_port *);
 static void MoxaPortFlushData(struct moxa_port *, int);
-static int MoxaPortWriteData(struct moxa_port *, const unsigned char *, int);
+static int MoxaPortWriteData(struct tty_struct *, const unsigned char *, int);
 static int MoxaPortReadData(struct moxa_port *);
 static int MoxaPortTxQueue(struct moxa_port *);
 static int MoxaPortRxQueue(struct moxa_port *);
@@ -332,6 +332,7 @@ static int moxa_ioctl(struct tty_struct *tty, struct file *file,
                for (i = 0; i < MAX_BOARDS; i++) {
                        p = moxa_boards[i].ports;
                        for (j = 0; j < MAX_PORTS_PER_BOARD; j++, p++, argm++) {
+                               struct tty_struct *ttyp;
                                memset(&tmp, 0, sizeof(tmp));
                                if (!moxa_boards[i].ready)
                                        goto copy;
@@ -344,10 +345,12 @@ static int moxa_ioctl(struct tty_struct *tty, struct file *file,
                                if (status & 4)
                                        tmp.dcd = 1;
 
-                               if (!p->port.tty || !p->port.tty->termios)
+                               ttyp = tty_port_tty_get(&p->port);
+                               if (!ttyp || !ttyp->termios)
                                        tmp.cflag = p->cflag;
                                else
-                                       tmp.cflag = p->port.tty->termios->c_cflag;
+                                       tmp.cflag = ttyp->termios->c_cflag;
+                               tty_kref_put(tty);
 copy:
                                if (copy_to_user(argm, &tmp, sizeof(tmp))) {
                                        mutex_unlock(&moxa_openlock);
@@ -880,8 +883,14 @@ static void moxa_board_deinit(struct moxa_board_conf *brd)
 
        /* pci hot-un-plug support */
        for (a = 0; a < brd->numPorts; a++)
-               if (brd->ports[a].port.flags & ASYNC_INITIALIZED)
-                       tty_hangup(brd->ports[a].port.tty);
+               if (brd->ports[a].port.flags & ASYNC_INITIALIZED) {
+                       struct tty_struct *tty = tty_port_tty_get(
+                                               &brd->ports[a].port);
+                       if (tty) {
+                               tty_hangup(tty);
+                               tty_kref_put(tty);
+                       }
+               }
        while (1) {
                opened = 0;
                for (a = 0; a < brd->numPorts; a++)
@@ -1096,13 +1105,14 @@ static void __exit moxa_exit(void)
 module_init(moxa_init);
 module_exit(moxa_exit);
 
-static void moxa_close_port(struct moxa_port *ch)
+static void moxa_close_port(struct tty_struct *tty)
 {
-       moxa_shut_down(ch);
+       struct moxa_port *ch = tty->driver_data;
+       moxa_shut_down(tty);
        MoxaPortFlushData(ch, 2);
        ch->port.flags &= ~ASYNC_NORMAL_ACTIVE;
-       ch->port.tty->driver_data = NULL;
-       ch->port.tty = NULL;
+       tty->driver_data = NULL;
+       tty_port_tty_set(&ch->port, NULL);
 }
 
 static int moxa_block_till_ready(struct tty_struct *tty, struct file *filp,
@@ -1161,7 +1171,7 @@ static int moxa_open(struct tty_struct *tty, struct file *filp)
        ch = &brd->ports[port % MAX_PORTS_PER_BOARD];
        ch->port.count++;
        tty->driver_data = ch;
-       ch->port.tty = tty;
+       tty_port_tty_set(&ch->port, tty);
        if (!(ch->port.flags & ASYNC_INITIALIZED)) {
                ch->statusflags = 0;
                moxa_set_tty_param(tty, tty->termios);
@@ -1179,7 +1189,7 @@ static int moxa_open(struct tty_struct *tty, struct file *filp)
        if (retval) {
                if (ch->port.count) /* 0 means already hung up... */
                        if (--ch->port.count == 0)
-                               moxa_close_port(ch);
+                               moxa_close_port(tty);
        } else
                ch->port.flags |= ASYNC_NORMAL_ACTIVE;
        mutex_unlock(&moxa_openlock);
@@ -1219,7 +1229,7 @@ static void moxa_close(struct tty_struct *tty, struct file *filp)
                tty_wait_until_sent(tty, 30 * HZ);      /* 30 seconds timeout */
        }
 
-       moxa_close_port(ch);
+       moxa_close_port(tty);
 unlock:
        mutex_unlock(&moxa_openlock);
 }
@@ -1234,7 +1244,7 @@ static int moxa_write(struct tty_struct *tty,
                return 0;
 
        spin_lock_bh(&moxa_lock);
-       len = MoxaPortWriteData(ch, buf, count);
+       len = MoxaPortWriteData(tty, buf, count);
        spin_unlock_bh(&moxa_lock);
 
        ch->statusflags |= LOWWAIT;
@@ -1409,7 +1419,7 @@ static void moxa_hangup(struct tty_struct *tty)
                return;
        }
        ch->port.count = 0;
-       moxa_close_port(ch);
+       moxa_close_port(tty);
        mutex_unlock(&moxa_openlock);
 
        wake_up_interruptible(&ch->port.open_wait);
@@ -1417,11 +1427,14 @@ static void moxa_hangup(struct tty_struct *tty)
 
 static void moxa_new_dcdstate(struct moxa_port *p, u8 dcd)
 {
+       struct tty_struct *tty;
        dcd = !!dcd;
 
-       if (dcd != p->DCDState && p->port.tty && C_CLOCAL(p->port.tty)) {
-               if (!dcd)
-                       tty_hangup(p->port.tty);
+       if (dcd != p->DCDState) {
+               tty = tty_port_tty_get(&p->port);
+               if (tty && C_CLOCAL(tty) && !dcd)
+                       tty_hangup(tty);
+               tty_kref_put(tty);
        }
        p->DCDState = dcd;
 }
@@ -1429,7 +1442,7 @@ static void moxa_new_dcdstate(struct moxa_port *p, u8 dcd)
 static int moxa_poll_port(struct moxa_port *p, unsigned int handle,
                u16 __iomem *ip)
 {
-       struct tty_struct *tty = p->port.tty;
+       struct tty_struct *tty = tty_port_tty_get(&p->port);
        void __iomem *ofsAddr;
        unsigned int inited = p->port.flags & ASYNC_INITIALIZED;
        u16 intr;
@@ -1476,6 +1489,7 @@ static int moxa_poll_port(struct moxa_port *p, unsigned int handle,
                tty_insert_flip_char(tty, 0, TTY_BREAK);
                tty_schedule_flip(tty);
        }
+       tty_kref_put(tty);
 
        if (intr & IntrLine)
                moxa_new_dcdstate(p, readb(ofsAddr + FlagStat) & DCD_state);
@@ -1560,9 +1574,9 @@ static void moxa_setup_empty_event(struct tty_struct *tty)
        spin_unlock_bh(&moxa_lock);
 }
 
-static void moxa_shut_down(struct moxa_port *ch)
+static void moxa_shut_down(struct tty_struct *tty)
 {
-       struct tty_struct *tp = ch->port.tty;
+       struct moxa_port *ch = tty->driver_data;
 
        if (!(ch->port.flags & ASYNC_INITIALIZED))
                return;
@@ -1572,7 +1586,7 @@ static void moxa_shut_down(struct moxa_port *ch)
        /*
         * If we're a modem control device and HUPCL is on, drop RTS & DTR.
         */
-       if (C_HUPCL(tp))
+       if (C_HUPCL(tty))
                MoxaPortLineCtrl(ch, 0, 0);
 
        spin_lock_bh(&moxa_lock);
@@ -1953,9 +1967,10 @@ static int MoxaPortLineStatus(struct moxa_port *port)
        return val;
 }
 
-static int MoxaPortWriteData(struct moxa_port *port,
+static int MoxaPortWriteData(struct tty_struct *tty,
                const unsigned char *buffer, int len)
 {
+       struct moxa_port *port = tty->driver_data;
        void __iomem *baseAddr, *ofsAddr, *ofs;
        unsigned int c, total;
        u16 head, tail, tx_mask, spage, epage;
index b638403e8e9c870af1d37cec1a44d5ffd54ae14f..8beef50f95a0929190e8321c49910f5c4b581ca0 100644 (file)
@@ -610,15 +610,13 @@ static int mxser_block_til_ready(struct tty_struct *tty, struct file *filp,
        return 0;
 }
 
-static int mxser_set_baud(struct mxser_port *info, long newspd)
+static int mxser_set_baud(struct tty_struct *tty, long newspd)
 {
+       struct mxser_port *info = tty->driver_data;
        int quot = 0, baud;
        unsigned char cval;
 
-       if (!info->port.tty || !info->port.tty->termios)
-               return -1;
-
-       if (!(info->ioaddr))
+       if (!info->ioaddr)
                return -1;
 
        if (newspd > info->max_baud)
@@ -626,13 +624,13 @@ static int mxser_set_baud(struct mxser_port *info, long newspd)
 
        if (newspd == 134) {
                quot = 2 * info->baud_base / 269;
-               tty_encode_baud_rate(info->port.tty, 134, 134);
+               tty_encode_baud_rate(tty, 134, 134);
        } else if (newspd) {
                quot = info->baud_base / newspd;
                if (quot == 0)
                        quot = 1;
                baud = info->baud_base/quot;
-               tty_encode_baud_rate(info->port.tty, baud, baud);
+               tty_encode_baud_rate(tty, baud, baud);
        } else {
                quot = 0;
        }
@@ -658,7 +656,7 @@ static int mxser_set_baud(struct mxser_port *info, long newspd)
        outb(cval, info->ioaddr + UART_LCR);    /* reset DLAB */
 
 #ifdef BOTHER
-       if (C_BAUD(info->port.tty) == BOTHER) {
+       if (C_BAUD(tty) == BOTHER) {
                quot = info->baud_base % newspd;
                quot *= 8;
                if (quot % newspd > newspd / 2) {
@@ -679,21 +677,20 @@ static int mxser_set_baud(struct mxser_port *info, long newspd)
  * This routine is called to set the UART divisor registers to match
  * the specified baud rate for a serial port.
  */
-static int mxser_change_speed(struct mxser_port *info,
-               struct ktermios *old_termios)
+static int mxser_change_speed(struct tty_struct *tty,
+                                       struct ktermios *old_termios)
 {
+       struct mxser_port *info = tty->driver_data;
        unsigned cflag, cval, fcr;
        int ret = 0;
        unsigned char status;
 
-       if (!info->port.tty || !info->port.tty->termios)
-               return ret;
-       cflag = info->port.tty->termios->c_cflag;
-       if (!(info->ioaddr))
+       cflag = tty->termios->c_cflag;
+       if (!info->ioaddr)
                return ret;
 
-       if (mxser_set_baud_method[info->port.tty->index] == 0)
-               mxser_set_baud(info, tty_get_baud_rate(info->port.tty));
+       if (mxser_set_baud_method[tty->index] == 0)
+               mxser_set_baud(tty, tty_get_baud_rate(tty));
 
        /* byte size and parity */
        switch (cflag & CSIZE) {
@@ -762,9 +759,9 @@ static int mxser_change_speed(struct mxser_port *info,
                        info->MCR |= UART_MCR_AFE;
                } else {
                        status = inb(info->ioaddr + UART_MSR);
-                       if (info->port.tty->hw_stopped) {
+                       if (tty->hw_stopped) {
                                if (status & UART_MSR_CTS) {
-                                       info->port.tty->hw_stopped = 0;
+                                       tty->hw_stopped = 0;
                                        if (info->type != PORT_16550A &&
                                                        !info->board->chip_flag) {
                                                outb(info->IER & ~UART_IER_THRI,
@@ -774,11 +771,11 @@ static int mxser_change_speed(struct mxser_port *info,
                                                outb(info->IER, info->ioaddr +
                                                                UART_IER);
                                        }
-                                       tty_wakeup(info->port.tty);
+                                       tty_wakeup(tty);
                                }
                        } else {
                                if (!(status & UART_MSR_CTS)) {
-                                       info->port.tty->hw_stopped = 1;
+                                       tty->hw_stopped = 1;
                                        if ((info->type != PORT_16550A) &&
                                                        (!info->board->chip_flag)) {
                                                info->IER &= ~UART_IER_THRI;
@@ -804,21 +801,21 @@ static int mxser_change_speed(struct mxser_port *info,
         * Set up parity check flag
         */
        info->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
-       if (I_INPCK(info->port.tty))
+       if (I_INPCK(tty))
                info->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
-       if (I_BRKINT(info->port.tty) || I_PARMRK(info->port.tty))
+       if (I_BRKINT(tty) || I_PARMRK(tty))
                info->read_status_mask |= UART_LSR_BI;
 
        info->ignore_status_mask = 0;
 
-       if (I_IGNBRK(info->port.tty)) {
+       if (I_IGNBRK(tty)) {
                info->ignore_status_mask |= UART_LSR_BI;
                info->read_status_mask |= UART_LSR_BI;
                /*
                 * If we're ignore parity and break indicators, ignore
                 * overruns too.  (For real raw support).
                 */
-               if (I_IGNPAR(info->port.tty)) {
+               if (I_IGNPAR(tty)) {
                        info->ignore_status_mask |=
                                                UART_LSR_OE |
                                                UART_LSR_PE |
@@ -830,16 +827,16 @@ static int mxser_change_speed(struct mxser_port *info,
                }
        }
        if (info->board->chip_flag) {
-               mxser_set_must_xon1_value(info->ioaddr, START_CHAR(info->port.tty));
-               mxser_set_must_xoff1_value(info->ioaddr, STOP_CHAR(info->port.tty));
-               if (I_IXON(info->port.tty)) {
+               mxser_set_must_xon1_value(info->ioaddr, START_CHAR(tty));
+               mxser_set_must_xoff1_value(info->ioaddr, STOP_CHAR(tty));
+               if (I_IXON(tty)) {
                        mxser_enable_must_rx_software_flow_control(
                                        info->ioaddr);
                } else {
                        mxser_disable_must_rx_software_flow_control(
                                        info->ioaddr);
                }
-               if (I_IXOFF(info->port.tty)) {
+               if (I_IXOFF(tty)) {
                        mxser_enable_must_tx_software_flow_control(
                                        info->ioaddr);
                } else {
@@ -855,7 +852,8 @@ static int mxser_change_speed(struct mxser_port *info,
        return ret;
 }
 
-static void mxser_check_modem_status(struct mxser_port *port, int status)
+static void mxser_check_modem_status(struct tty_struct *tty,
+                               struct mxser_port *port, int status)
 {
        /* update input line counters */
        if (status & UART_MSR_TERI)
@@ -874,10 +872,11 @@ static void mxser_check_modem_status(struct mxser_port *port, int status)
                        wake_up_interruptible(&port->port.open_wait);
        }
 
+       tty = tty_port_tty_get(&port->port);
        if (port->port.flags & ASYNC_CTS_FLOW) {
-               if (port->port.tty->hw_stopped) {
+               if (tty->hw_stopped) {
                        if (status & UART_MSR_CTS) {
-                               port->port.tty->hw_stopped = 0;
+                               tty->hw_stopped = 0;
 
                                if ((port->type != PORT_16550A) &&
                                                (!port->board->chip_flag)) {
@@ -887,11 +886,11 @@ static void mxser_check_modem_status(struct mxser_port *port, int status)
                                        outb(port->IER, port->ioaddr +
                                                        UART_IER);
                                }
-                               tty_wakeup(port->port.tty);
+                               tty_wakeup(tty);
                        }
                } else {
                        if (!(status & UART_MSR_CTS)) {
-                               port->port.tty->hw_stopped = 1;
+                               tty->hw_stopped = 1;
                                if (port->type != PORT_16550A &&
                                                !port->board->chip_flag) {
                                        port->IER &= ~UART_IER_THRI;
@@ -903,8 +902,9 @@ static void mxser_check_modem_status(struct mxser_port *port, int status)
        }
 }
 
-static int mxser_startup(struct mxser_port *info)
+static int mxser_startup(struct tty_struct *tty)
 {
+       struct mxser_port *info = tty->driver_data;
        unsigned long page;
        unsigned long flags;
 
@@ -921,8 +921,7 @@ static int mxser_startup(struct mxser_port *info)
        }
 
        if (!info->ioaddr || !info->type) {
-               if (info->port.tty)
-                       set_bit(TTY_IO_ERROR, &info->port.tty->flags);
+               set_bit(TTY_IO_ERROR, &tty->flags);
                free_page(page);
                spin_unlock_irqrestore(&info->slock, flags);
                return 0;
@@ -952,8 +951,8 @@ static int mxser_startup(struct mxser_port *info)
        if (inb(info->ioaddr + UART_LSR) == 0xff) {
                spin_unlock_irqrestore(&info->slock, flags);
                if (capable(CAP_SYS_ADMIN)) {
-                       if (info->port.tty)
-                               set_bit(TTY_IO_ERROR, &info->port.tty->flags);
+                       if (tty)
+                               set_bit(TTY_IO_ERROR, &tty->flags);
                        return 0;
                } else
                        return -ENODEV;
@@ -991,14 +990,13 @@ static int mxser_startup(struct mxser_port *info)
        (void) inb(info->ioaddr + UART_IIR);
        (void) inb(info->ioaddr + UART_MSR);
 
-       if (info->port.tty)
-               clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
+       clear_bit(TTY_IO_ERROR, &tty->flags);
        info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
 
        /*
         * and set the speed of the serial port
         */
-       mxser_change_speed(info, NULL);
+       mxser_change_speed(tty, NULL);
        info->port.flags |= ASYNC_INITIALIZED;
        spin_unlock_irqrestore(&info->slock, flags);
 
@@ -1009,8 +1007,9 @@ static int mxser_startup(struct mxser_port *info)
  * This routine will shutdown a serial port; interrupts maybe disabled, and
  * DTR is dropped if the hangup on close termio flag is on.
  */
-static void mxser_shutdown(struct mxser_port *info)
+static void mxser_shutdown(struct tty_struct *tty)
 {
+       struct mxser_port *info = tty->driver_data;
        unsigned long flags;
 
        if (!(info->port.flags & ASYNC_INITIALIZED))
@@ -1035,7 +1034,7 @@ static void mxser_shutdown(struct mxser_port *info)
        info->IER = 0;
        outb(0x00, info->ioaddr + UART_IER);
 
-       if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL))
+       if (tty->termios->c_cflag & HUPCL)
                info->MCR &= ~(UART_MCR_DTR | UART_MCR_RTS);
        outb(info->MCR, info->ioaddr + UART_MCR);
 
@@ -1051,8 +1050,7 @@ static void mxser_shutdown(struct mxser_port *info)
        /* read data port to reset things */
        (void) inb(info->ioaddr + UART_RX);
 
-       if (info->port.tty)
-               set_bit(TTY_IO_ERROR, &info->port.tty->flags);
+       set_bit(TTY_IO_ERROR, &tty->flags);
 
        info->port.flags &= ~ASYNC_INITIALIZED;
 
@@ -1084,14 +1082,14 @@ static int mxser_open(struct tty_struct *tty, struct file *filp)
                return -ENODEV;
 
        tty->driver_data = info;
-       info->port.tty = tty;
+       tty_port_tty_set(&info->port, tty);
        /*
         * Start up serial port
         */
        spin_lock_irqsave(&info->slock, flags);
        info->port.count++;
        spin_unlock_irqrestore(&info->slock, flags);
-       retval = mxser_startup(info);
+       retval = mxser_startup(tty);
        if (retval)
                return retval;
 
@@ -1209,13 +1207,13 @@ static void mxser_close(struct tty_struct *tty, struct file *filp)
                                break;
                }
        }
-       mxser_shutdown(info);
+       mxser_shutdown(tty);
 
        mxser_flush_buffer(tty);
        tty_ldisc_flush(tty);
 
        tty->closing = 0;
-       info->port.tty = NULL;
+       tty_port_tty_set(&info->port, NULL);
        if (info->port.blocked_open) {
                if (info->port.close_delay)
                        schedule_timeout_interruptible(info->port.close_delay);
@@ -1337,12 +1335,13 @@ static int mxser_chars_in_buffer(struct tty_struct *tty)
  * friends of mxser_ioctl()
  * ------------------------------------------------------------
  */
-static int mxser_get_serial_info(struct mxser_port *info,
+static int mxser_get_serial_info(struct tty_struct *tty,
                struct serial_struct __user *retinfo)
 {
+       struct mxser_port *info = tty->driver_data;
        struct serial_struct tmp = {
                .type = info->type,
-               .line = info->port.tty->index,
+               .line = tty->index,
                .port = info->ioaddr,
                .irq = info->board->irq,
                .flags = info->port.flags,
@@ -1357,9 +1356,10 @@ static int mxser_get_serial_info(struct mxser_port *info,
        return 0;
 }
 
-static int mxser_set_serial_info(struct mxser_port *info,
+static int mxser_set_serial_info(struct tty_struct *tty,
                struct serial_struct __user *new_info)
 {
+       struct mxser_port *info = tty->driver_data;
        struct serial_struct new_serial;
        speed_t baud;
        unsigned long sl_flags;
@@ -1393,14 +1393,14 @@ static int mxser_set_serial_info(struct mxser_port *info,
                                (new_serial.flags & ASYNC_FLAGS));
                info->port.close_delay = new_serial.close_delay * HZ / 100;
                info->port.closing_wait = new_serial.closing_wait * HZ / 100;
-               info->port.tty->low_latency =
-                               (info->port.flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+               tty->low_latency = (info->port.flags & ASYNC_LOW_LATENCY)
+                                                               ? 1 : 0;
                if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST &&
                                (new_serial.baud_base != info->baud_base ||
                                new_serial.custom_divisor !=
                                info->custom_divisor)) {
                        baud = new_serial.baud_base / new_serial.custom_divisor;
-                       tty_encode_baud_rate(info->port.tty, baud, baud);
+                       tty_encode_baud_rate(tty, baud, baud);
                }
        }
 
@@ -1411,11 +1411,11 @@ static int mxser_set_serial_info(struct mxser_port *info,
        if (info->port.flags & ASYNC_INITIALIZED) {
                if (flags != (info->port.flags & ASYNC_SPD_MASK)) {
                        spin_lock_irqsave(&info->slock, sl_flags);
-                       mxser_change_speed(info, NULL);
+                       mxser_change_speed(tty, NULL);
                        spin_unlock_irqrestore(&info->slock, sl_flags);
                }
        } else
-               retval = mxser_startup(info);
+               retval = mxser_startup(tty);
 
        return retval;
 }
@@ -1461,7 +1461,7 @@ static int mxser_tiocmget(struct tty_struct *tty, struct file *file)
        spin_lock_irqsave(&info->slock, flags);
        status = inb(info->ioaddr + UART_MSR);
        if (status & UART_MSR_ANY_DELTA)
-               mxser_check_modem_status(info, status);
+               mxser_check_modem_status(tty, info, status);
        spin_unlock_irqrestore(&info->slock, flags);
        return ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) |
                    ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) |
@@ -1606,6 +1606,7 @@ static int __init mxser_read_register(int port, unsigned short *regs)
 static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
 {
        struct mxser_port *port;
+       struct tty_struct *tty;
        int result, status;
        unsigned int i, j;
        int ret = 0;
@@ -1643,12 +1644,14 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
 
                                if (!port->ioaddr)
                                        goto copy;
+                               
+                               tty = tty_port_tty_get(&port->port);
 
-                               if (!port->port.tty || !port->port.tty->termios)
+                               if (!tty || !tty->termios)
                                        ms.cflag = port->normal_termios.c_cflag;
                                else
-                                       ms.cflag = port->port.tty->termios->c_cflag;
-
+                                       ms.cflag = tty->termios->c_cflag;
+                               tty_kref_put(tty);
                                status = inb(port->ioaddr + UART_MSR);
                                if (status & UART_MSR_DCD)
                                        ms.dcd = 1;
@@ -1704,15 +1707,18 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
                                me->up_txcnt[p] = port->mon_data.up_txcnt;
                                me->modem_status[p] =
                                        port->mon_data.modem_status;
-                               me->baudrate[p] = tty_get_baud_rate(port->port.tty);
+                               tty = tty_port_tty_get(&port->port);
 
-                               if (!port->port.tty || !port->port.tty->termios) {
+                               if (!tty || !tty->termios) {
                                        cflag = port->normal_termios.c_cflag;
                                        iflag = port->normal_termios.c_iflag;
+                                       me->baudrate[p] = tty_termios_baud_rate(&port->normal_termios);
                                } else {
-                                       cflag = port->port.tty->termios->c_cflag;
-                                       iflag = port->port.tty->termios->c_iflag;
+                                       cflag = tty->termios->c_cflag;
+                                       iflag = tty->termios->c_iflag;
+                                       me->baudrate[p] = tty_get_baud_rate(tty);
                                }
+                               tty_kref_put(tty);
 
                                me->databits[p] = cflag & CSIZE;
                                me->stopbits[p] = cflag & CSTOPB;
@@ -1822,12 +1828,12 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
        switch (cmd) {
        case TIOCGSERIAL:
                lock_kernel();
-               retval = mxser_get_serial_info(info, argp);
+               retval = mxser_get_serial_info(tty, argp);
                unlock_kernel();
                return retval;
        case TIOCSSERIAL:
                lock_kernel();
-               retval = mxser_set_serial_info(info, argp);
+               retval = mxser_set_serial_info(tty, argp);
                unlock_kernel();
                return retval;
        case TIOCSERGETLSR:     /* Get line status register */
@@ -1896,7 +1902,7 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
 
                lock_kernel();
                status = mxser_get_msr(info->ioaddr, 1, tty->index);
-               mxser_check_modem_status(info, status);
+               mxser_check_modem_status(tty, info, status);
 
                mcr = inb(info->ioaddr + UART_MCR);
                if (mcr & MOXA_MUST_MCR_XON_FLAG)
@@ -1909,7 +1915,7 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
                else
                        info->mon_data.hold_reason |= NPPI_NOTIFY_XOFFXENT;
 
-               if (info->port.tty->hw_stopped)
+               if (tty->hw_stopped)
                        info->mon_data.hold_reason |= NPPI_NOTIFY_CTSHOLD;
                else
                        info->mon_data.hold_reason &= ~NPPI_NOTIFY_CTSHOLD;
@@ -1958,7 +1964,7 @@ static void mxser_stoprx(struct tty_struct *tty)
                }
        }
 
-       if (info->port.tty->termios->c_cflag & CRTSCTS) {
+       if (tty->termios->c_cflag & CRTSCTS) {
                info->MCR &= ~UART_MCR_RTS;
                outb(info->MCR, info->ioaddr + UART_MCR);
        }
@@ -1995,7 +2001,7 @@ static void mxser_unthrottle(struct tty_struct *tty)
                }
        }
 
-       if (info->port.tty->termios->c_cflag & CRTSCTS) {
+       if (tty->termios->c_cflag & CRTSCTS) {
                info->MCR |= UART_MCR_RTS;
                outb(info->MCR, info->ioaddr + UART_MCR);
        }
@@ -2040,7 +2046,7 @@ static void mxser_set_termios(struct tty_struct *tty, struct ktermios *old_termi
        unsigned long flags;
 
        spin_lock_irqsave(&info->slock, flags);
-       mxser_change_speed(info, old_termios);
+       mxser_change_speed(tty, old_termios);
        spin_unlock_irqrestore(&info->slock, flags);
 
        if ((old_termios->c_cflag & CRTSCTS) &&
@@ -2138,10 +2144,10 @@ static void mxser_hangup(struct tty_struct *tty)
        struct mxser_port *info = tty->driver_data;
 
        mxser_flush_buffer(tty);
-       mxser_shutdown(info);
+       mxser_shutdown(tty);
        info->port.count = 0;
        info->port.flags &= ~ASYNC_NORMAL_ACTIVE;
-       info->port.tty = NULL;
+       tty_port_tty_set(&info->port, NULL);
        wake_up_interruptible(&info->port.open_wait);
 }
 
@@ -2164,9 +2170,9 @@ static int mxser_rs_break(struct tty_struct *tty, int break_state)
        return 0;
 }
 
-static void mxser_receive_chars(struct mxser_port *port, int *status)
+static void mxser_receive_chars(struct tty_struct *tty,
+                               struct mxser_port *port, int *status)
 {
-       struct tty_struct *tty = port->port.tty;
        unsigned char ch, gdl;
        int ignored = 0;
        int cnt = 0;
@@ -2174,9 +2180,8 @@ static void mxser_receive_chars(struct mxser_port *port, int *status)
        int max = 256;
 
        recv_room = tty->receive_room;
-       if ((recv_room == 0) && (!port->ldisc_stop_rx))
+       if (recv_room == 0 && !port->ldisc_stop_rx)
                mxser_stoprx(tty);
-
        if (port->board->chip_flag != MOXA_OTHER_UART) {
 
                if (*status & UART_LSR_SPECIAL)
@@ -2253,7 +2258,7 @@ intr_old:
        } while (*status & UART_LSR_DR);
 
 end_intr:
-       mxvar_log.rxcnt[port->port.tty->index] += cnt;
+       mxvar_log.rxcnt[tty->index] += cnt;
        port->mon_data.rxcnt += cnt;
        port->mon_data.up_rxcnt += cnt;
 
@@ -2267,14 +2272,14 @@ end_intr:
        spin_lock(&port->slock);
 }
 
-static void mxser_transmit_chars(struct mxser_port *port)
+static void mxser_transmit_chars(struct tty_struct *tty, struct mxser_port *port)
 {
        int count, cnt;
 
        if (port->x_char) {
                outb(port->x_char, port->ioaddr + UART_TX);
                port->x_char = 0;
-               mxvar_log.txcnt[port->port.tty->index]++;
+               mxvar_log.txcnt[tty->index]++;
                port->mon_data.txcnt++;
                port->mon_data.up_txcnt++;
                port->icount.tx++;
@@ -2284,8 +2289,8 @@ static void mxser_transmit_chars(struct mxser_port *port)
        if (port->port.xmit_buf == NULL)
                return;
 
-       if ((port->xmit_cnt <= 0) || port->port.tty->stopped ||
-                       (port->port.tty->hw_stopped &&
+       if (port->xmit_cnt <= 0 || tty->stopped ||
+                       (tty->hw_stopped &&
                        (port->type != PORT_16550A) &&
                        (!port->board->chip_flag))) {
                port->IER &= ~UART_IER_THRI;
@@ -2302,14 +2307,14 @@ static void mxser_transmit_chars(struct mxser_port *port)
                if (--port->xmit_cnt <= 0)
                        break;
        } while (--count > 0);
-       mxvar_log.txcnt[port->port.tty->index] += (cnt - port->xmit_cnt);
+       mxvar_log.txcnt[tty->index] += (cnt - port->xmit_cnt);
 
        port->mon_data.txcnt += (cnt - port->xmit_cnt);
        port->mon_data.up_txcnt += (cnt - port->xmit_cnt);
        port->icount.tx += (cnt - port->xmit_cnt);
 
-       if (port->xmit_cnt < WAKEUP_CHARS)
-               tty_wakeup(port->port.tty);
+       if (port->xmit_cnt < WAKEUP_CHARS && tty)
+               tty_wakeup(tty);
 
        if (port->xmit_cnt <= 0) {
                port->IER &= ~UART_IER_THRI;
@@ -2328,6 +2333,7 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id)
        int max, irqbits, bits, msr;
        unsigned int int_cnt, pass_counter = 0;
        int handled = IRQ_NONE;
+       struct tty_struct *tty;
 
        for (i = 0; i < MXSER_BOARDS; i++)
                if (dev_id == &mxser_boards[i]) {
@@ -2360,13 +2366,15 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id)
                                if (iir & UART_IIR_NO_INT)
                                        break;
                                iir &= MOXA_MUST_IIR_MASK;
-                               if (!port->port.tty ||
+                               tty = tty_port_tty_get(&port->port);
+                               if (!tty ||
                                                (port->port.flags & ASYNC_CLOSING) ||
                                                !(port->port.flags &
                                                        ASYNC_INITIALIZED)) {
                                        status = inb(port->ioaddr + UART_LSR);
                                        outb(0x27, port->ioaddr + UART_FCR);
                                        inb(port->ioaddr + UART_MSR);
+                                       tty_kref_put(tty);
                                        break;
                                }
 
@@ -2387,27 +2395,28 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id)
                                            iir == MOXA_MUST_IIR_RDA ||
                                            iir == MOXA_MUST_IIR_RTO ||
                                            iir == MOXA_MUST_IIR_LSR)
-                                               mxser_receive_chars(port,
+                                               mxser_receive_chars(tty, port,
                                                                &status);
 
                                } else {
                                        status &= port->read_status_mask;
                                        if (status & UART_LSR_DR)
-                                               mxser_receive_chars(port,
+                                               mxser_receive_chars(tty, port,
                                                                &status);
                                }
                                msr = inb(port->ioaddr + UART_MSR);
                                if (msr & UART_MSR_ANY_DELTA)
-                                       mxser_check_modem_status(port, msr);
+                                       mxser_check_modem_status(tty, port, msr);
 
                                if (port->board->chip_flag) {
                                        if (iir == 0x02 && (status &
                                                                UART_LSR_THRE))
-                                               mxser_transmit_chars(port);
+                                               mxser_transmit_chars(tty, port);
                                } else {
                                        if (status & UART_LSR_THRE)
-                                               mxser_transmit_chars(port);
+                                               mxser_transmit_chars(tty, port);
                                }
+                               tty_kref_put(tty);
                        } while (int_cnt++ < MXSER_ISR_PASS_LIMIT);
                        spin_unlock(&port->slock);
                }
index 69ec6399c714b206ea11de8c30d8ba75fd0a9bd6..bacb3e2872ae49cbc5668e6a402cb50fbf75a30b 100644 (file)
@@ -764,7 +764,7 @@ static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file,
                break;
 
        default:
-               error = n_tty_ioctl (tty, file, cmd, arg);
+               error = n_tty_ioctl_helper(tty, file, cmd, arg);
                break;
        }
        return error;
index ae377aa473ba6fbe5644ac47866fd9637fc1499b..4a8215a89ad3fe4287b0f5f4560844b0c3cb4b2e 100644 (file)
@@ -372,14 +372,8 @@ static void remove_from_rx_queue(struct r3964_info *pInfo,
 static void put_char(struct r3964_info *pInfo, unsigned char ch)
 {
        struct tty_struct *tty = pInfo->tty;
-
-       if (tty == NULL)
-               return;
-
        /* FIXME: put_char should not be called from an IRQ */
-       if (tty->ops->put_char) {
-               tty->ops->put_char(tty, ch);
-       }
+       tty_put_char(tty, ch);
        pInfo->bcc ^= ch;
 }
 
index 708c2b1dbe51068a5d1b91ba27d38d79d0c39308..efbfe9612658bc5cd32b0e36c77e8651a3363746 100644 (file)
@@ -26,7 +26,7 @@
  *
  * 2002/03/18   Implemented n_tty_wakeup to send SIGIO POLL_OUTs to
  *             waiting writing processes-Sapan Bhatia <sapan@corewars.org>.
- *             Also fixed a bug in BLOCKING mode where write_chan returns
+ *             Also fixed a bug in BLOCKING mode where n_tty_write returns
  *             EAGAIN
  */
 
@@ -99,6 +99,7 @@ static inline int tty_put_user(struct tty_struct *tty, unsigned char x,
 
 static void n_tty_set_room(struct tty_struct *tty)
 {
+       /* tty->read_cnt is not read locked ? */
        int     left = N_TTY_BUF_SIZE - tty->read_cnt - 1;
 
        /*
@@ -121,6 +122,16 @@ static void put_tty_queue_nolock(unsigned char c, struct tty_struct *tty)
        }
 }
 
+/**
+ *     put_tty_queue           -       add character to tty
+ *     @c: character
+ *     @tty: tty device
+ *
+ *     Add a character to the tty read_buf queue. This is done under the
+ *     read_lock to serialize character addition and also to protect us
+ *     against parallel reads or flushes
+ */
+
 static void put_tty_queue(unsigned char c, struct tty_struct *tty)
 {
        unsigned long flags;
@@ -137,14 +148,11 @@ static void put_tty_queue(unsigned char c, struct tty_struct *tty)
  *     check_unthrottle        -       allow new receive data
  *     @tty; tty device
  *
- *     Check whether to call the driver.unthrottle function.
- *     We test the TTY_THROTTLED bit first so that it always
- *     indicates the current state. The decision about whether
- *     it is worth allowing more input has been taken by the caller.
+ *     Check whether to call the driver unthrottle functions
+ *
  *     Can sleep, may be called under the atomic_read_lock mutex but
  *     this is not guaranteed.
  */
-
 static void check_unthrottle(struct tty_struct *tty)
 {
        if (tty->count)
@@ -158,6 +166,8 @@ static void check_unthrottle(struct tty_struct *tty)
  *     Reset the read buffer counters, clear the flags,
  *     and make sure the driver is unthrottled. Called
  *     from n_tty_open() and n_tty_flush_buffer().
+ *
+ *     Locking: tty_read_lock for read fields.
  */
 static void reset_buffer_flags(struct tty_struct *tty)
 {
@@ -181,7 +191,7 @@ static void reset_buffer_flags(struct tty_struct *tty)
  *     at hangup) or when the N_TTY line discipline internally has to
  *     clean the pending queue (for example some signals).
  *
- *     Locking: ctrl_lock
+ *     Locking: ctrl_lock, read_lock.
  */
 
 static void n_tty_flush_buffer(struct tty_struct *tty)
@@ -207,6 +217,8 @@ static void n_tty_flush_buffer(struct tty_struct *tty)
  *
  *     Report the number of characters buffered to be delivered to user
  *     at this instant in time.
+ *
+ *     Locking: read_lock
  */
 
 static ssize_t n_tty_chars_in_buffer(struct tty_struct *tty)
@@ -346,7 +358,7 @@ static int opost(unsigned char c, struct tty_struct *tty)
  *     the simple cases normally found and helps to generate blocks of
  *     symbols for the console driver and thus improve performance.
  *
- *     Called from write_chan under the tty layer write lock. Relies
+ *     Called from n_tty_write under the tty layer write lock. Relies
  *     on lock_kernel for the tty->column state.
  */
 
@@ -410,6 +422,8 @@ break_out:
  *
  *     Echo user input back onto the screen. This must be called only when
  *     L_ECHO(tty) is true. Called from the driver receive_buf path.
+ *
+ *     Relies on BKL for tty column locking
  */
 
 static void echo_char(unsigned char c, struct tty_struct *tty)
@@ -422,6 +436,12 @@ static void echo_char(unsigned char c, struct tty_struct *tty)
                opost(c, tty);
 }
 
+/**
+ *     finsh_erasing           -       complete erase
+ *     @tty: tty doing the erase
+ *
+ *     Relies on BKL for tty column locking
+ */
 static inline void finish_erasing(struct tty_struct *tty)
 {
        if (tty->erasing) {
@@ -439,6 +459,8 @@ static inline void finish_erasing(struct tty_struct *tty)
  *     Perform erase and necessary output when an erase character is
  *     present in the stream from the driver layer. Handles the complexities
  *     of UTF-8 multibyte symbols.
+ *
+ *     Locking: read_lock for tty buffers, BKL for column/erasing state
  */
 
 static void eraser(unsigned char c, struct tty_struct *tty)
@@ -447,6 +469,7 @@ static void eraser(unsigned char c, struct tty_struct *tty)
        int head, seen_alnums, cnt;
        unsigned long flags;
 
+       /* FIXME: locking needed ? */
        if (tty->read_head == tty->canon_head) {
                /* opost('\a', tty); */         /* what do you think? */
                return;
@@ -481,6 +504,7 @@ static void eraser(unsigned char c, struct tty_struct *tty)
        }
 
        seen_alnums = 0;
+       /* FIXME: Locking ?? */
        while (tty->read_head != tty->canon_head) {
                head = tty->read_head;
 
@@ -583,6 +607,8 @@ static void eraser(unsigned char c, struct tty_struct *tty)
  *     may caus terminal flushing to take place according to the termios
  *     settings and character used. Called from the driver receive_buf
  *     path so serialized.
+ *
+ *     Locking: ctrl_lock, read_lock (both via flush buffer)
  */
 
 static inline void isig(int sig, struct tty_struct *tty, int flush)
@@ -1007,12 +1033,26 @@ int is_ignored(int sig)
  *     and is protected from re-entry by the tty layer. The user is
  *     guaranteed that this function will not be re-entered or in progress
  *     when the ldisc is closed.
+ *
+ *     Locking: Caller holds tty->termios_mutex
  */
 
 static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
 {
-       if (!tty)
-               return;
+       int canon_change = 1;
+       BUG_ON(!tty);
+
+       if (old)
+               canon_change = (old->c_lflag ^ tty->termios->c_lflag) & ICANON;
+       if (canon_change) {
+               memset(&tty->read_flags, 0, sizeof tty->read_flags);
+               tty->canon_head = tty->read_tail;
+               tty->canon_data = 0;
+               tty->erasing = 0;
+       }
+
+       if (canon_change && !L_ICANON(tty) && tty->read_cnt)
+               wake_up_interruptible(&tty->read_wait);
 
        tty->icanon = (L_ICANON(tty) != 0);
        if (test_bit(TTY_HW_COOK_IN, &tty->flags)) {
@@ -1143,7 +1183,7 @@ static inline int input_available_p(struct tty_struct *tty, int amt)
  *     @b: user data
  *     @nr: size of data
  *
- *     Helper function to speed up read_chan.  It is only called when
+ *     Helper function to speed up n_tty_read.  It is only called when
  *     ICANON is off; it copies characters straight from the tty queue to
  *     user space directly.  It can be profitably called twice; once to
  *     drain the space from the tail pointer to the (physical) end of the
@@ -1210,7 +1250,7 @@ static int job_control(struct tty_struct *tty, struct file *file)
        if (file->f_op->write != redirected_tty_write &&
            current->signal->tty == tty) {
                if (!tty->pgrp)
-                       printk(KERN_ERR "read_chan: no tty->pgrp!\n");
+                       printk(KERN_ERR "n_tty_read: no tty->pgrp!\n");
                else if (task_pgrp(current) != tty->pgrp) {
                        if (is_ignored(SIGTTIN) ||
                            is_current_pgrp_orphaned())
@@ -1225,7 +1265,7 @@ static int job_control(struct tty_struct *tty, struct file *file)
 
 
 /**
- *     read_chan               -       read function for tty
+ *     n_tty_read              -       read function for tty
  *     @tty: tty device
  *     @file: file object
  *     @buf: userspace buffer pointer
@@ -1239,7 +1279,7 @@ static int job_control(struct tty_struct *tty, struct file *file)
  *     This code must be sure never to sleep through a hangup.
  */
 
-static ssize_t read_chan(struct tty_struct *tty, struct file *file,
+static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
                         unsigned char __user *buf, size_t nr)
 {
        unsigned char __user *b = buf;
@@ -1254,10 +1294,7 @@ static ssize_t read_chan(struct tty_struct *tty, struct file *file,
 
 do_it_again:
 
-       if (!tty->read_buf) {
-               printk(KERN_ERR "n_tty_read_chan: read_buf == NULL?!?\n");
-               return -EIO;
-       }
+       BUG_ON(!tty->read_buf);
 
        c = job_control(tty, file);
        if (c < 0)
@@ -1444,7 +1481,7 @@ do_it_again:
 }
 
 /**
- *     write_chan              -       write function for tty
+ *     n_tty_write             -       write function for tty
  *     @tty: tty device
  *     @file: file object
  *     @buf: userspace buffer pointer
@@ -1458,7 +1495,7 @@ do_it_again:
  *     This code must be sure never to sleep through a hangup.
  */
 
-static ssize_t write_chan(struct tty_struct *tty, struct file *file,
+static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
                          const unsigned char *buf, size_t nr)
 {
        const unsigned char *b = buf;
@@ -1532,7 +1569,7 @@ break_out:
 }
 
 /**
- *     normal_poll             -       poll method for N_TTY
+ *     n_tty_poll              -       poll method for N_TTY
  *     @tty: terminal device
  *     @file: file accessing it
  *     @wait: poll table
@@ -1545,7 +1582,7 @@ break_out:
  *     Called without the kernel lock held - fine
  */
 
-static unsigned int normal_poll(struct tty_struct *tty, struct file *file,
+static unsigned int n_tty_poll(struct tty_struct *tty, struct file *file,
                                                        poll_table *wait)
 {
        unsigned int mask = 0;
@@ -1573,6 +1610,44 @@ static unsigned int normal_poll(struct tty_struct *tty, struct file *file,
        return mask;
 }
 
+static unsigned long inq_canon(struct tty_struct *tty)
+{
+       int nr, head, tail;
+
+       if (!tty->canon_data)
+               return 0;
+       head = tty->canon_head;
+       tail = tty->read_tail;
+       nr = (head - tail) & (N_TTY_BUF_SIZE-1);
+       /* Skip EOF-chars.. */
+       while (head != tail) {
+               if (test_bit(tail, tty->read_flags) &&
+                   tty->read_buf[tail] == __DISABLED_CHAR)
+                       nr--;
+               tail = (tail+1) & (N_TTY_BUF_SIZE-1);
+       }
+       return nr;
+}
+
+static int n_tty_ioctl(struct tty_struct *tty, struct file *file,
+                      unsigned int cmd, unsigned long arg)
+{
+       int retval;
+
+       switch (cmd) {
+       case TIOCOUTQ:
+               return put_user(tty_chars_in_buffer(tty), (int __user *) arg);
+       case TIOCINQ:
+               /* FIXME: Locking */
+               retval = tty->read_cnt;
+               if (L_ICANON(tty))
+                       retval = inq_canon(tty);
+               return put_user(retval, (unsigned int __user *) arg);
+       default:
+               return n_tty_ioctl_helper(tty, file, cmd, arg);
+       }
+}
+
 struct tty_ldisc_ops tty_ldisc_N_TTY = {
        .magic           = TTY_LDISC_MAGIC,
        .name            = "n_tty",
@@ -1580,11 +1655,11 @@ struct tty_ldisc_ops tty_ldisc_N_TTY = {
        .close           = n_tty_close,
        .flush_buffer    = n_tty_flush_buffer,
        .chars_in_buffer = n_tty_chars_in_buffer,
-       .read            = read_chan,
-       .write           = write_chan,
+       .read            = n_tty_read,
+       .write           = n_tty_write,
        .ioctl           = n_tty_ioctl,
        .set_termios     = n_tty_set_termios,
-       .poll            = normal_poll,
+       .poll            = n_tty_poll,
        .receive_buf     = n_tty_receive_buf,
        .write_wakeup    = n_tty_write_wakeup
 };
index 66a0f931c66ca91bf06b56e0b789edb8a0d68204..9a34a1935283370a837bd0c72fa5d05463ff2ae7 100644 (file)
@@ -1599,7 +1599,10 @@ static int ntty_open(struct tty_struct *tty, struct file *file)
        return 0;
 }
 
-/* Called when the userspace process close the tty, /dev/noz*. */
+/* Called when the userspace process close the tty, /dev/noz*. Also
+   called immediately if ntty_open fails in which case tty->driver_data
+   will be NULL an we exit by the first return */
+
 static void ntty_close(struct tty_struct *tty, struct file *file)
 {
        struct nozomi *dc = get_dc_by_tty(tty);
index 3a23e7694d55f2c61374139117c23dc20c52052b..569f2f7743a78ddc80f4e7714c6456506b8a4995 100644 (file)
@@ -276,6 +276,7 @@ static int ipw_write_room(struct tty_struct *linux_tty)
        struct ipw_tty *tty = linux_tty->driver_data;
        int room;
 
+       /* FIXME: Exactly how is the tty object locked here .. */
        if (!tty)
                return -ENODEV;
 
@@ -397,6 +398,7 @@ static int set_control_lines(struct ipw_tty *tty, unsigned int set,
 static int ipw_tiocmget(struct tty_struct *linux_tty, struct file *file)
 {
        struct ipw_tty *tty = linux_tty->driver_data;
+       /* FIXME: Exactly how is the tty object locked here .. */
 
        if (!tty)
                return -ENODEV;
@@ -412,6 +414,7 @@ ipw_tiocmset(struct tty_struct *linux_tty, struct file *file,
             unsigned int set, unsigned int clear)
 {
        struct ipw_tty *tty = linux_tty->driver_data;
+       /* FIXME: Exactly how is the tty object locked here .. */
 
        if (!tty)
                return -ENODEV;
@@ -433,6 +436,8 @@ static int ipw_ioctl(struct tty_struct *linux_tty, struct file *file,
        if (!tty->open_count)
                return -EINVAL;
 
+       /* FIXME: Exactly how is the tty object locked here .. */
+
        switch (cmd) {
        case TIOCGSERIAL:
                return ipwireless_get_serial_info(tty, (void __user *) arg);
@@ -467,13 +472,6 @@ static int ipw_ioctl(struct tty_struct *linux_tty, struct file *file,
                        }
                        return 0;
 
-               case TCGETS:
-               case TCGETA:
-                       return n_tty_ioctl(linux_tty, file, cmd, arg);
-
-               case TCFLSH:
-                       return n_tty_ioctl(linux_tty, file, cmd, arg);
-
                case FIONREAD:
                        {
                                int val = 0;
@@ -482,10 +480,11 @@ static int ipw_ioctl(struct tty_struct *linux_tty, struct file *file,
                                        return -EFAULT;
                        }
                        return 0;
+               case TCFLSH:
+                       return tty_perform_flush(linux_tty, arg);
                }
        }
-
-       return -ENOIOCTLCMD;
+       return tty_mode_ioctl(linux_tty, file, cmd , arg);
 }
 
 static int add_tty(dev_node_t *nodesp, int j,
@@ -588,6 +587,8 @@ void ipwireless_tty_free(struct ipw_tty *tty)
                                tty_hangup(ttyj->linux_tty);
                                /* Wait till the tty_hangup has completed */
                                flush_scheduled_work();
+                               /* FIXME: Exactly how is the tty object locked here
+                                  against a parallel ioctl etc */
                                mutex_lock(&ttyj->ipw_tty_mutex);
                        }
                        while (ttyj->open_count)
index 76b27932d229df31d3ff24f7d09e83afecdb278a..6d4582712b1fa6ae1a1c40fbb792a3f863681657 100644 (file)
@@ -8,10 +8,12 @@
  *  Added TTY_DO_WRITE_WAKEUP to enable n_tty to send POLL_OUT to
  *      waiting writers -- Sapan Bhatia <sapan@corewars.org>
  *
- *
+ *  When reading this code see also fs/devpts. In particular note that the
+ *  driver_data field is used by the devpts side as a binding to the devpts
+ *  inode.
  */
 
-#include <linux/module.h>      /* For EXPORT_SYMBOL */
+#include <linux/module.h>
 
 #include <linux/errno.h>
 #include <linux/interrupt.h>
 #include <linux/mm.h>
 #include <linux/init.h>
 #include <linux/sysctl.h>
-
-#include <asm/uaccess.h>
-#include <asm/system.h>
+#include <linux/device.h>
+#include <linux/uaccess.h>
 #include <linux/bitops.h>
 #include <linux/devpts_fs.h>
 
+#include <asm/system.h>
+
 /* These are global because they are accessed in tty_io.c */
 #ifdef CONFIG_UNIX98_PTYS
 struct tty_driver *ptm_driver;
 static struct tty_driver *pts_driver;
 #endif
 
-static void pty_close(struct tty_struct * tty, struct file * filp)
+static void pty_close(struct tty_struct *tty, struct file *filp)
 {
-       if (!tty)
-               return;
-       if (tty->driver->subtype == PTY_TYPE_MASTER) {
-               if (tty->count > 1)
-                       printk("master pty_close: count = %d!!\n", tty->count);
-       } else {
+       BUG_ON(!tty);
+       if (tty->driver->subtype == PTY_TYPE_MASTER)
+               WARN_ON(tty->count > 1);
+       else {
                if (tty->count > 2)
                        return;
        }
@@ -59,7 +60,7 @@ static void pty_close(struct tty_struct * tty, struct file * filp)
                set_bit(TTY_OTHER_CLOSED, &tty->flags);
 #ifdef CONFIG_UNIX98_PTYS
                if (tty->driver == ptm_driver)
-                       devpts_pty_kill(tty->index);
+                       devpts_pty_kill(tty->link);
 #endif
                tty_vhangup(tty->link);
        }
@@ -69,13 +70,13 @@ static void pty_close(struct tty_struct * tty, struct file * filp)
  * The unthrottle routine is called by the line discipline to signal
  * that it can receive more characters.  For PTY's, the TTY_THROTTLED
  * flag is always set, to force the line discipline to always call the
- * unthrottle routine when there are fewer than TTY_THRESHOLD_UNTHROTTLE 
+ * unthrottle routine when there are fewer than TTY_THRESHOLD_UNTHROTTLE
  * characters in the queue.  This is necessary since each time this
  * happens, we need to wake up any sleeping processes that could be
  * (1) trying to send data to the pty, or (2) waiting in wait_until_sent()
  * for the pty buffer to be drained.
  */
-static void pty_unthrottle(struct tty_struct * tty)
+static void pty_unthrottle(struct tty_struct *tty)
 {
        struct tty_struct *o_tty = tty->link;
 
@@ -87,7 +88,7 @@ static void pty_unthrottle(struct tty_struct * tty)
 }
 
 /*
- * WSH 05/24/97: modified to 
+ * WSH 05/24/97: modified to
  *   (1) use space in tty->flip instead of a shared temp buffer
  *      The flip buffers aren't being used for a pty, so there's lots
  *      of space available.  The buffer is protected by a per-pty
@@ -100,7 +101,8 @@ static void pty_unthrottle(struct tty_struct * tty)
  * not our partners. We can't just take the other one blindly without
  * risking deadlocks.
  */
-static int pty_write(struct tty_struct * tty, const unsigned char *buf, int count)
+static int pty_write(struct tty_struct *tty, const unsigned char *buf,
+                                                               int count)
 {
        struct tty_struct *to = tty->link;
        int     c;
@@ -112,7 +114,7 @@ static int pty_write(struct tty_struct * tty, const unsigned char *buf, int coun
        if (c > count)
                c = count;
        to->ldisc.ops->receive_buf(to, buf, NULL, c);
-       
+
        return c;
 }
 
@@ -128,17 +130,17 @@ static int pty_write_room(struct tty_struct *tty)
 
 /*
  *     WSH 05/24/97:  Modified for asymmetric MASTER/SLAVE behavior
- *     The chars_in_buffer() value is used by the ldisc select() function 
+ *     The chars_in_buffer() value is used by the ldisc select() function
  *     to hold off writing when chars_in_buffer > WAKEUP_CHARS (== 256).
  *     The pty driver chars_in_buffer() Master/Slave must behave differently:
  *
  *      The Master side needs to allow typed-ahead commands to accumulate
  *      while being canonicalized, so we report "our buffer" as empty until
  *     some threshold is reached, and then report the count. (Any count >
- *     WAKEUP_CHARS is regarded by select() as "full".)  To avoid deadlock 
- *     the count returned must be 0 if no canonical data is available to be 
+ *     WAKEUP_CHARS is regarded by select() as "full".)  To avoid deadlock
+ *     the count returned must be 0 if no canonical data is available to be
  *     read. (The N_TTY ldisc.chars_in_buffer now knows this.)
- *  
+ *
  *     The Slave side passes all characters in raw mode to the Master side's
  *     buffer where they can be read immediately, so in this case we can
  *     return the true count in the buffer.
@@ -155,21 +157,22 @@ static int pty_chars_in_buffer(struct tty_struct *tty)
        /* The ldisc must report 0 if no characters available to be read */
        count = to->ldisc.ops->chars_in_buffer(to);
 
-       if (tty->driver->subtype == PTY_TYPE_SLAVE) return count;
+       if (tty->driver->subtype == PTY_TYPE_SLAVE)
+               return count;
 
-       /* Master side driver ... if the other side's read buffer is less than 
+       /* Master side driver ... if the other side's read buffer is less than
         * half full, return 0 to allow writers to proceed; otherwise return
-        * the count.  This leaves a comfortable margin to avoid overflow, 
+        * the count.  This leaves a comfortable margin to avoid overflow,
         * and still allows half a buffer's worth of typed-ahead commands.
         */
-       return ((count < N_TTY_BUF_SIZE/2) ? 0 : count);
+       return (count < N_TTY_BUF_SIZE/2) ? 0 : count;
 }
 
 /* Set the lock flag on a pty */
-static int pty_set_lock(struct tty_struct *tty, int __user * arg)
+static int pty_set_lock(struct tty_struct *tty, int __user *arg)
 {
        int val;
-       if (get_user(val,arg))
+       if (get_user(val, arg))
                return -EFAULT;
        if (val)
                set_bit(TTY_PTY_LOCK, &tty->flags);
@@ -182,13 +185,13 @@ static void pty_flush_buffer(struct tty_struct *tty)
 {
        struct tty_struct *to = tty->link;
        unsigned long flags;
-       
+
        if (!to)
                return;
-       
+
        if (to->ldisc.ops->flush_buffer)
                to->ldisc.ops->flush_buffer(to);
-       
+
        if (to->packet) {
                spin_lock_irqsave(&tty->ctrl_lock, flags);
                tty->ctrl_status |= TIOCPKT_FLUSHWRITE;
@@ -197,7 +200,7 @@ static void pty_flush_buffer(struct tty_struct *tty)
        }
 }
 
-static int pty_open(struct tty_struct *tty, struct file * filp)
+static int pty_open(struct tty_struct *tty, struct file *filp)
 {
        int     retval = -ENODEV;
 
@@ -220,13 +223,65 @@ out:
        return retval;
 }
 
-static void pty_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
+static void pty_set_termios(struct tty_struct *tty,
+                                       struct ktermios *old_termios)
+{
+       tty->termios->c_cflag &= ~(CSIZE | PARENB);
+       tty->termios->c_cflag |= (CS8 | CREAD);
+}
+
+static int pty_install(struct tty_driver *driver, struct tty_struct *tty)
 {
-        tty->termios->c_cflag &= ~(CSIZE | PARENB);
-        tty->termios->c_cflag |= (CS8 | CREAD);
+       struct tty_struct *o_tty;
+       int idx = tty->index;
+       int retval;
+
+       o_tty = alloc_tty_struct();
+       if (!o_tty)
+               return -ENOMEM;
+       if (!try_module_get(driver->other->owner)) {
+               /* This cannot in fact currently happen */
+               free_tty_struct(o_tty);
+               return -ENOMEM;
+       }
+       initialize_tty_struct(o_tty, driver->other, idx);
+
+       /* We always use new tty termios data so we can do this
+          the easy way .. */
+       retval = tty_init_termios(tty);
+       if (retval)
+               goto free_mem_out;
+
+       retval = tty_init_termios(o_tty);
+       if (retval) {
+               tty_free_termios(tty);
+               goto free_mem_out;
+       }
+
+       /*
+        * Everything allocated ... set up the o_tty structure.
+        */
+       driver->other->ttys[idx] = o_tty;
+       tty_driver_kref_get(driver->other);
+       if (driver->subtype == PTY_TYPE_MASTER)
+               o_tty->count++;
+       /* Establish the links in both directions */
+       tty->link   = o_tty;
+       o_tty->link = tty;
+
+       tty_driver_kref_get(driver);
+       tty->count++;
+       driver->ttys[idx] = tty;
+       return 0;
+free_mem_out:
+       module_put(o_tty->driver->owner);
+       free_tty_struct(o_tty);
+       return -ENOMEM;
 }
 
+
 static const struct tty_operations pty_ops = {
+       .install = pty_install,
        .open = pty_open,
        .close = pty_close,
        .write = pty_write,
@@ -329,8 +384,11 @@ static inline void legacy_pty_init(void) { }
  * Otherwise one can eat up all kernel memory by opening /dev/ptmx repeatedly.
  */
 int pty_limit = NR_UNIX98_PTY_DEFAULT;
-static int pty_limit_min = 0;
+static int pty_limit_min;
 static int pty_limit_max = NR_UNIX98_PTY_MAX;
+static int pty_count;
+
+static struct cdev ptmx_cdev;
 
 static struct ctl_table pty_table[] = {
        {
@@ -348,6 +406,7 @@ static struct ctl_table pty_table[] = {
                .procname       = "nr",
                .maxlen         = sizeof(int),
                .mode           = 0444,
+               .data           = &pty_count,
                .proc_handler   = &proc_dointvec,
        }, {
                .ctl_name       = 0
@@ -388,7 +447,127 @@ static int pty_unix98_ioctl(struct tty_struct *tty, struct file *file,
        return -ENOIOCTLCMD;
 }
 
+/**
+ *     ptm_unix98_lookup       -       find a pty master
+ *     @driver: ptm driver
+ *     @idx: tty index
+ *
+ *     Look up a pty master device. Called under the tty_mutex for now.
+ *     This provides our locking.
+ */
+
+static struct tty_struct *ptm_unix98_lookup(struct tty_driver *driver,
+               struct inode *ptm_inode, int idx)
+{
+       struct tty_struct *tty = devpts_get_tty(ptm_inode, idx);
+       if (tty)
+               tty = tty->link;
+       return tty;
+}
+
+/**
+ *     pts_unix98_lookup       -       find a pty slave
+ *     @driver: pts driver
+ *     @idx: tty index
+ *
+ *     Look up a pty master device. Called under the tty_mutex for now.
+ *     This provides our locking.
+ */
+
+static struct tty_struct *pts_unix98_lookup(struct tty_driver *driver,
+               struct inode *pts_inode, int idx)
+{
+       struct tty_struct *tty = devpts_get_tty(pts_inode, idx);
+       /* Master must be open before slave */
+       if (!tty)
+               return ERR_PTR(-EIO);
+       return tty;
+}
+
+static void pty_unix98_shutdown(struct tty_struct *tty)
+{
+       /* We have our own method as we don't use the tty index */
+       kfree(tty->termios);
+}
+
+/* We have no need to install and remove our tty objects as devpts does all
+   the work for us */
+
+static int pty_unix98_install(struct tty_driver *driver, struct tty_struct *tty)
+{
+       struct tty_struct *o_tty;
+       int idx = tty->index;
+
+       o_tty = alloc_tty_struct();
+       if (!o_tty)
+               return -ENOMEM;
+       if (!try_module_get(driver->other->owner)) {
+               /* This cannot in fact currently happen */
+               free_tty_struct(o_tty);
+               return -ENOMEM;
+       }
+       initialize_tty_struct(o_tty, driver->other, idx);
+
+       tty->termios = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL);
+       if (tty->termios == NULL)
+               goto free_mem_out;
+       *tty->termios = driver->init_termios;
+       tty->termios_locked = tty->termios + 1;
+
+       o_tty->termios = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL);
+       if (o_tty->termios == NULL)
+               goto free_mem_out;
+       *o_tty->termios = driver->other->init_termios;
+       o_tty->termios_locked = o_tty->termios + 1;
+
+       tty_driver_kref_get(driver->other);
+       if (driver->subtype == PTY_TYPE_MASTER)
+               o_tty->count++;
+       /* Establish the links in both directions */
+       tty->link   = o_tty;
+       o_tty->link = tty;
+       /*
+        * All structures have been allocated, so now we install them.
+        * Failures after this point use release_tty to clean up, so
+        * there's no need to null out the local pointers.
+        */
+       tty_driver_kref_get(driver);
+       tty->count++;
+       pty_count++;
+       return 0;
+free_mem_out:
+       kfree(o_tty->termios);
+       module_put(o_tty->driver->owner);
+       free_tty_struct(o_tty);
+       kfree(tty->termios);
+       return -ENOMEM;
+}
+
+static void pty_unix98_remove(struct tty_driver *driver, struct tty_struct *tty)
+{
+       pty_count--;
+}
+
+static const struct tty_operations ptm_unix98_ops = {
+       .lookup = ptm_unix98_lookup,
+       .install = pty_unix98_install,
+       .remove = pty_unix98_remove,
+       .open = pty_open,
+       .close = pty_close,
+       .write = pty_write,
+       .write_room = pty_write_room,
+       .flush_buffer = pty_flush_buffer,
+       .chars_in_buffer = pty_chars_in_buffer,
+       .unthrottle = pty_unthrottle,
+       .set_termios = pty_set_termios,
+       .ioctl = pty_unix98_ioctl,
+       .shutdown = pty_unix98_shutdown
+};
+
 static const struct tty_operations pty_unix98_ops = {
+       .lookup = pts_unix98_lookup,
+       .install = pty_unix98_install,
+       .remove = pty_unix98_remove,
        .open = pty_open,
        .close = pty_close,
        .write = pty_write,
@@ -397,9 +576,73 @@ static const struct tty_operations pty_unix98_ops = {
        .chars_in_buffer = pty_chars_in_buffer,
        .unthrottle = pty_unthrottle,
        .set_termios = pty_set_termios,
-       .ioctl = pty_unix98_ioctl
+       .shutdown = pty_unix98_shutdown
 };
 
+/**
+ *     ptmx_open               -       open a unix 98 pty master
+ *     @inode: inode of device file
+ *     @filp: file pointer to tty
+ *
+ *     Allocate a unix98 pty master device from the ptmx driver.
+ *
+ *     Locking: tty_mutex protects the init_dev work. tty->count should
+ *             protect the rest.
+ *             allocated_ptys_lock handles the list of free pty numbers
+ */
+
+static int __ptmx_open(struct inode *inode, struct file *filp)
+{
+       struct tty_struct *tty;
+       int retval;
+       int index;
+
+       nonseekable_open(inode, filp);
+
+       /* find a device that is not in use. */
+       index = devpts_new_index(inode);
+       if (index < 0)
+               return index;
+
+       mutex_lock(&tty_mutex);
+       tty = tty_init_dev(ptm_driver, index, 1);
+       mutex_unlock(&tty_mutex);
+
+       if (IS_ERR(tty)) {
+               retval = PTR_ERR(tty);
+               goto out;
+       }
+
+       set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
+       filp->private_data = tty;
+       file_move(filp, &tty->tty_files);
+
+       retval = devpts_pty_new(inode, tty->link);
+       if (retval)
+               goto out1;
+
+       retval = ptm_driver->ops->open(tty, filp);
+       if (!retval)
+               return 0;
+out1:
+       tty_release_dev(filp);
+       return retval;
+out:
+       devpts_kill_index(inode, index);
+       return retval;
+}
+
+static int ptmx_open(struct inode *inode, struct file *filp)
+{
+       int ret;
+
+       lock_kernel();
+       ret = __ptmx_open(inode, filp);
+       unlock_kernel();
+       return ret;
+}
+
+static struct file_operations ptmx_fops;
 
 static void __init unix98_pty_init(void)
 {
@@ -427,7 +670,7 @@ static void __init unix98_pty_init(void)
        ptm_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW |
                TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM;
        ptm_driver->other = pts_driver;
-       tty_set_operations(ptm_driver, &pty_unix98_ops);
+       tty_set_operations(ptm_driver, &ptm_unix98_ops);
 
        pts_driver->owner = THIS_MODULE;
        pts_driver->driver_name = "pty_slave";
@@ -443,16 +686,26 @@ static void __init unix98_pty_init(void)
        pts_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW |
                TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM;
        pts_driver->other = ptm_driver;
-       tty_set_operations(pts_driver, &pty_ops);
-       
+       tty_set_operations(pts_driver, &pty_unix98_ops);
+
        if (tty_register_driver(ptm_driver))
                panic("Couldn't register Unix98 ptm driver");
        if (tty_register_driver(pts_driver))
                panic("Couldn't register Unix98 pts driver");
 
-       pty_table[1].data = &ptm_driver->refcount;
        register_sysctl_table(pty_root_table);
+
+       /* Now create the /dev/ptmx special device */
+       tty_default_fops(&ptmx_fops);
+       ptmx_fops.open = ptmx_open;
+
+       cdev_init(&ptmx_cdev, &ptmx_fops);
+       if (cdev_add(&ptmx_cdev, MKDEV(TTYAUX_MAJOR, 2), 1) ||
+           register_chrdev_region(MKDEV(TTYAUX_MAJOR, 2), 1, "/dev/ptmx") < 0)
+               panic("Couldn't register /dev/ptmx driver\n");
+       device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx");
 }
+
 #else
 static inline void unix98_pty_init(void) { }
 #endif
index 19db1eb87c26fa22eb9e4f17d8b6ec384e6c021b..8b8f07a7f50529f1e67eaac40f0a4c43f4f1b0ed 100644 (file)
@@ -405,9 +405,9 @@ static unsigned int stl_baudrates[] = {
 
 static int     stl_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg);
 static int     stl_brdinit(struct stlbrd *brdp);
-static int     stl_getportstats(struct stlport *portp, comstats_t __user *cp);
+static int     stl_getportstats(struct tty_struct *tty, struct stlport *portp, comstats_t __user *cp);
 static int     stl_clrportstats(struct stlport *portp, comstats_t __user *cp);
-static int     stl_waitcarrier(struct stlport *portp, struct file *filp);
+static int     stl_waitcarrier(struct tty_struct *tty, struct stlport *portp, struct file *filp);
 
 /*
  *     CD1400 uart specific handling functions.
@@ -612,8 +612,9 @@ static struct class *stallion_class;
 static void stl_cd_change(struct stlport *portp)
 {
        unsigned int oldsigs = portp->sigs;
+       struct tty_struct *tty = tty_port_tty_get(&portp->port);
 
-       if (!portp->port.tty)
+       if (!tty)
                return;
 
        portp->sigs = stl_getsignals(portp);
@@ -623,7 +624,8 @@ static void stl_cd_change(struct stlport *portp)
 
        if ((oldsigs & TIOCM_CD) && ((portp->sigs & TIOCM_CD) == 0))
                if (portp->port.flags & ASYNC_CHECK_CD)
-                       tty_hangup(portp->port.tty);
+                       tty_hangup(tty);
+       tty_kref_put(tty);
 }
 
 /*
@@ -734,7 +736,7 @@ static int stl_open(struct tty_struct *tty, struct file *filp)
  *     On the first open of the device setup the port hardware, and
  *     initialize the per port data structure.
  */
-       portp->port.tty = tty;
+       tty_port_tty_set(&portp->port, tty);
        tty->driver_data = portp;
        portp->port.count++;
 
@@ -774,7 +776,7 @@ static int stl_open(struct tty_struct *tty, struct file *filp)
  *     then also we might have to wait for carrier.
  */
        if (!(filp->f_flags & O_NONBLOCK))
-               if ((rc = stl_waitcarrier(portp, filp)) != 0)
+               if ((rc = stl_waitcarrier(tty, portp, filp)) != 0)
                        return rc;
 
        portp->port.flags |= ASYNC_NORMAL_ACTIVE;
@@ -789,7 +791,8 @@ static int stl_open(struct tty_struct *tty, struct file *filp)
  *     maybe because if we are clocal then we don't need to wait...
  */
 
-static int stl_waitcarrier(struct stlport *portp, struct file *filp)
+static int stl_waitcarrier(struct tty_struct *tty, struct stlport *portp,
+                                                       struct file *filp)
 {
        unsigned long   flags;
        int             rc, doclocal;
@@ -801,7 +804,7 @@ static int stl_waitcarrier(struct stlport *portp, struct file *filp)
 
        spin_lock_irqsave(&stallion_lock, flags);
 
-       if (portp->port.tty->termios->c_cflag & CLOCAL)
+       if (tty->termios->c_cflag & CLOCAL)
                doclocal++;
 
        portp->openwaitcnt++;
@@ -846,8 +849,6 @@ static void stl_flushbuffer(struct tty_struct *tty)
 
        pr_debug("stl_flushbuffer(tty=%p)\n", tty);
 
-       if (tty == NULL)
-               return;
        portp = tty->driver_data;
        if (portp == NULL)
                return;
@@ -865,8 +866,6 @@ static void stl_waituntilsent(struct tty_struct *tty, int timeout)
 
        pr_debug("stl_waituntilsent(tty=%p,timeout=%d)\n", tty, timeout);
 
-       if (tty == NULL)
-               return;
        portp = tty->driver_data;
        if (portp == NULL)
                return;
@@ -949,7 +948,7 @@ static void stl_close(struct tty_struct *tty, struct file *filp)
        tty_ldisc_flush(tty);
 
        tty->closing = 0;
-       portp->port.tty = NULL;
+       tty_port_tty_set(&portp->port, NULL);
 
        if (portp->openwaitcnt) {
                if (portp->close_delay)
@@ -1033,8 +1032,6 @@ static int stl_putchar(struct tty_struct *tty, unsigned char ch)
 
        pr_debug("stl_putchar(tty=%p,ch=%x)\n", tty, ch);
 
-       if (tty == NULL)
-               return -EINVAL;
        portp = tty->driver_data;
        if (portp == NULL)
                return -EINVAL;
@@ -1070,8 +1067,6 @@ static void stl_flushchars(struct tty_struct *tty)
 
        pr_debug("stl_flushchars(tty=%p)\n", tty);
 
-       if (tty == NULL)
-               return;
        portp = tty->driver_data;
        if (portp == NULL)
                return;
@@ -1090,8 +1085,6 @@ static int stl_writeroom(struct tty_struct *tty)
 
        pr_debug("stl_writeroom(tty=%p)\n", tty);
 
-       if (tty == NULL)
-               return 0;
        portp = tty->driver_data;
        if (portp == NULL)
                return 0;
@@ -1122,8 +1115,6 @@ static int stl_charsinbuffer(struct tty_struct *tty)
 
        pr_debug("stl_charsinbuffer(tty=%p)\n", tty);
 
-       if (tty == NULL)
-               return 0;
        portp = tty->driver_data;
        if (portp == NULL)
                return 0;
@@ -1183,8 +1174,9 @@ static int stl_getserial(struct stlport *portp, struct serial_struct __user *sp)
  *     just quietly ignore any requests to change irq, etc.
  */
 
-static int stl_setserial(struct stlport *portp, struct serial_struct __user *sp)
+static int stl_setserial(struct tty_struct *tty, struct serial_struct __user *sp)
 {
+       struct stlport *        portp = tty->driver_data;
        struct serial_struct    sio;
 
        pr_debug("stl_setserial(portp=%p,sp=%p)\n", portp, sp);
@@ -1205,7 +1197,7 @@ static int stl_setserial(struct stlport *portp, struct serial_struct __user *sp)
        portp->close_delay = sio.close_delay;
        portp->closing_wait = sio.closing_wait;
        portp->custom_divisor = sio.custom_divisor;
-       stl_setport(portp, portp->port.tty->termios);
+       stl_setport(portp, tty->termios);
        return 0;
 }
 
@@ -1215,8 +1207,6 @@ static int stl_tiocmget(struct tty_struct *tty, struct file *file)
 {
        struct stlport  *portp;
 
-       if (tty == NULL)
-               return -ENODEV;
        portp = tty->driver_data;
        if (portp == NULL)
                return -ENODEV;
@@ -1232,8 +1222,6 @@ static int stl_tiocmset(struct tty_struct *tty, struct file *file,
        struct stlport  *portp;
        int rts = -1, dtr = -1;
 
-       if (tty == NULL)
-               return -ENODEV;
        portp = tty->driver_data;
        if (portp == NULL)
                return -ENODEV;
@@ -1262,8 +1250,6 @@ static int stl_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd
        pr_debug("stl_ioctl(tty=%p,file=%p,cmd=%x,arg=%lx)\n", tty, file, cmd,
                        arg);
 
-       if (tty == NULL)
-               return -ENODEV;
        portp = tty->driver_data;
        if (portp == NULL)
                return -ENODEV;
@@ -1282,10 +1268,10 @@ static int stl_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd
                rc = stl_getserial(portp, argp);
                break;
        case TIOCSSERIAL:
-               rc = stl_setserial(portp, argp);
+               rc = stl_setserial(tty, argp);
                break;
        case COM_GETPORTSTATS:
-               rc = stl_getportstats(portp, argp);
+               rc = stl_getportstats(tty, portp, argp);
                break;
        case COM_CLRPORTSTATS:
                rc = stl_clrportstats(portp, argp);
@@ -1317,8 +1303,6 @@ static void stl_start(struct tty_struct *tty)
 
        pr_debug("stl_start(tty=%p)\n", tty);
 
-       if (tty == NULL)
-               return;
        portp = tty->driver_data;
        if (portp == NULL)
                return;
@@ -1334,8 +1318,6 @@ static void stl_settermios(struct tty_struct *tty, struct ktermios *old)
 
        pr_debug("stl_settermios(tty=%p,old=%p)\n", tty, old);
 
-       if (tty == NULL)
-               return;
        portp = tty->driver_data;
        if (portp == NULL)
                return;
@@ -1369,8 +1351,6 @@ static void stl_throttle(struct tty_struct *tty)
 
        pr_debug("stl_throttle(tty=%p)\n", tty);
 
-       if (tty == NULL)
-               return;
        portp = tty->driver_data;
        if (portp == NULL)
                return;
@@ -1389,8 +1369,6 @@ static void stl_unthrottle(struct tty_struct *tty)
 
        pr_debug("stl_unthrottle(tty=%p)\n", tty);
 
-       if (tty == NULL)
-               return;
        portp = tty->driver_data;
        if (portp == NULL)
                return;
@@ -1410,8 +1388,6 @@ static void stl_stop(struct tty_struct *tty)
 
        pr_debug("stl_stop(tty=%p)\n", tty);
 
-       if (tty == NULL)
-               return;
        portp = tty->driver_data;
        if (portp == NULL)
                return;
@@ -1432,8 +1408,6 @@ static void stl_hangup(struct tty_struct *tty)
 
        pr_debug("stl_hangup(tty=%p)\n", tty);
 
-       if (tty == NULL)
-               return;
        portp = tty->driver_data;
        if (portp == NULL)
                return;
@@ -1452,7 +1426,7 @@ static void stl_hangup(struct tty_struct *tty)
                portp->tx.head = NULL;
                portp->tx.tail = NULL;
        }
-       portp->port.tty = NULL;
+       tty_port_tty_set(&portp->port, NULL);
        portp->port.flags &= ~ASYNC_NORMAL_ACTIVE;
        portp->port.count = 0;
        wake_up_interruptible(&portp->port.open_wait);
@@ -1466,8 +1440,6 @@ static int stl_breakctl(struct tty_struct *tty, int state)
 
        pr_debug("stl_breakctl(tty=%p,state=%d)\n", tty, state);
 
-       if (tty == NULL)
-               return -EINVAL;
        portp = tty->driver_data;
        if (portp == NULL)
                return -EINVAL;
@@ -1484,8 +1456,6 @@ static void stl_sendxchar(struct tty_struct *tty, char ch)
 
        pr_debug("stl_sendxchar(tty=%p,ch=%x)\n", tty, ch);
 
-       if (tty == NULL)
-               return;
        portp = tty->driver_data;
        if (portp == NULL)
                return;
@@ -1805,7 +1775,7 @@ static int __devinit stl_initports(struct stlbrd *brdp, struct stlpanel *panelp)
                                "(size=%Zd)\n", sizeof(struct stlport));
                        break;
                }
-
+               tty_port_init(&portp->port);
                portp->magic = STL_PORTMAGIC;
                portp->portnr = i;
                portp->brdnr = panelp->brdnr;
@@ -1832,6 +1802,7 @@ static void stl_cleanup_panels(struct stlbrd *brdp)
        struct stlpanel *panelp;
        struct stlport *portp;
        unsigned int j, k;
+       struct tty_struct *tty;
 
        for (j = 0; j < STL_MAXPANELS; j++) {
                panelp = brdp->panels[j];
@@ -1841,8 +1812,11 @@ static void stl_cleanup_panels(struct stlbrd *brdp)
                        portp = panelp->ports[k];
                        if (portp == NULL)
                                continue;
-                       if (portp->port.tty != NULL)
-                               stl_hangup(portp->port.tty);
+                       tty = tty_port_tty_get(&portp->port);
+                       if (tty != NULL) {
+                               stl_hangup(tty);
+                               tty_kref_put(tty);
+                       }
                        kfree(portp->tx.buf);
                        kfree(portp);
                }
@@ -2498,7 +2472,7 @@ static struct stlport *stl_getport(int brdnr, int panelnr, int portnr)
  *     what port to get stats for (used through board control device).
  */
 
-static int stl_getportstats(struct stlport *portp, comstats_t __user *cp)
+static int stl_getportstats(struct tty_struct *tty, struct stlport *portp, comstats_t __user *cp)
 {
        comstats_t      stl_comstats;
        unsigned char   *head, *tail;
@@ -2525,18 +2499,17 @@ static int stl_getportstats(struct stlport *portp, comstats_t __user *cp)
        portp->stats.rxbuffered = 0;
 
        spin_lock_irqsave(&stallion_lock, flags);
-       if (portp->port.tty != NULL)
-               if (portp->port.tty->driver_data == portp) {
-                       portp->stats.ttystate = portp->port.tty->flags;
-                       /* No longer available as a statistic */
-                       portp->stats.rxbuffered = 1; /*portp->port.tty->flip.count; */
-                       if (portp->port.tty->termios != NULL) {
-                               portp->stats.cflags = portp->port.tty->termios->c_cflag;
-                               portp->stats.iflags = portp->port.tty->termios->c_iflag;
-                               portp->stats.oflags = portp->port.tty->termios->c_oflag;
-                               portp->stats.lflags = portp->port.tty->termios->c_lflag;
-                       }
+       if (tty != NULL && portp->port.tty == tty) {
+               portp->stats.ttystate = tty->flags;
+               /* No longer available as a statistic */
+               portp->stats.rxbuffered = 1; /*tty->flip.count; */
+               if (tty->termios != NULL) {
+                       portp->stats.cflags = tty->termios->c_cflag;
+                       portp->stats.iflags = tty->termios->c_iflag;
+                       portp->stats.oflags = tty->termios->c_oflag;
+                       portp->stats.lflags = tty->termios->c_lflag;
                }
+       }
        spin_unlock_irqrestore(&stallion_lock, flags);
 
        head = portp->tx.head;
@@ -2640,7 +2613,7 @@ static int stl_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, uns
 
        switch (cmd) {
        case COM_GETPORTSTATS:
-               rc = stl_getportstats(NULL, argp);
+               rc = stl_getportstats(NULL, NULL, argp);
                break;
        case COM_CLRPORTSTATS:
                rc = stl_clrportstats(NULL, argp);
@@ -3243,7 +3216,7 @@ static void stl_cd1400flowctrl(struct stlport *portp, int state)
 
        if (portp == NULL)
                return;
-       tty = portp->port.tty;
+       tty = tty_port_tty_get(&portp->port);
        if (tty == NULL)
                return;
 
@@ -3288,6 +3261,7 @@ static void stl_cd1400flowctrl(struct stlport *portp, int state)
 
        BRDDISABLE(portp->brdnr);
        spin_unlock_irqrestore(&brd_lock, flags);
+       tty_kref_put(tty);
 }
 
 /*****************************************************************************/
@@ -3305,7 +3279,7 @@ static void stl_cd1400sendflow(struct stlport *portp, int state)
 
        if (portp == NULL)
                return;
-       tty = portp->port.tty;
+       tty = tty_port_tty_get(&portp->port);
        if (tty == NULL)
                return;
 
@@ -3325,6 +3299,7 @@ static void stl_cd1400sendflow(struct stlport *portp, int state)
        }
        BRDDISABLE(portp->brdnr);
        spin_unlock_irqrestore(&brd_lock, flags);
+       tty_kref_put(tty);
 }
 
 /*****************************************************************************/
@@ -3478,6 +3453,7 @@ static void stl_cd1400txisr(struct stlpanel *panelp, int ioaddr)
        int             len, stlen;
        char            *head, *tail;
        unsigned char   ioack, srer;
+       struct tty_struct *tty;
 
        pr_debug("stl_cd1400txisr(panelp=%p,ioaddr=%x)\n", panelp, ioaddr);
 
@@ -3504,8 +3480,11 @@ static void stl_cd1400txisr(struct stlpanel *panelp, int ioaddr)
        if ((len == 0) || ((len < STL_TXBUFLOW) &&
            (test_bit(ASYI_TXLOW, &portp->istate) == 0))) {
                set_bit(ASYI_TXLOW, &portp->istate);
-               if (portp->port.tty)
-                       tty_wakeup(portp->port.tty);
+               tty = tty_port_tty_get(&portp->port);
+               if (tty) {
+                       tty_wakeup(tty);
+                       tty_kref_put(tty);
+               }
        }
 
        if (len == 0) {
@@ -3569,7 +3548,7 @@ static void stl_cd1400rxisr(struct stlpanel *panelp, int ioaddr)
                return;
        }
        portp = panelp->ports[(ioack >> 3)];
-       tty = portp->port.tty;
+       tty = tty_port_tty_get(&portp->port);
 
        if ((ioack & ACK_TYPMASK) == ACK_TYPRXGOOD) {
                outb((RDCR + portp->uartaddr), ioaddr);
@@ -3633,10 +3612,12 @@ static void stl_cd1400rxisr(struct stlpanel *panelp, int ioaddr)
                }
        } else {
                printk("STALLION: bad RX interrupt ack value=%x\n", ioack);
+               tty_kref_put(tty);
                return;
        }
 
 stl_rxalldone:
+       tty_kref_put(tty);
        outb((EOSRR + portp->uartaddr), ioaddr);
        outb(0, (ioaddr + EREG_DATA));
 }
@@ -4175,7 +4156,7 @@ static void stl_sc26198flowctrl(struct stlport *portp, int state)
 
        if (portp == NULL)
                return;
-       tty = portp->port.tty;
+       tty = tty_port_tty_get(&portp->port);
        if (tty == NULL)
                return;
 
@@ -4226,6 +4207,7 @@ static void stl_sc26198flowctrl(struct stlport *portp, int state)
 
        BRDDISABLE(portp->brdnr);
        spin_unlock_irqrestore(&brd_lock, flags);
+       tty_kref_put(tty);
 }
 
 /*****************************************************************************/
@@ -4244,7 +4226,7 @@ static void stl_sc26198sendflow(struct stlport *portp, int state)
 
        if (portp == NULL)
                return;
-       tty = portp->port.tty;
+       tty = tty_port_tty_get(&portp->port);
        if (tty == NULL)
                return;
 
@@ -4269,6 +4251,7 @@ static void stl_sc26198sendflow(struct stlport *portp, int state)
        }
        BRDDISABLE(portp->brdnr);
        spin_unlock_irqrestore(&brd_lock, flags);
+       tty_kref_put(tty);
 }
 
 /*****************************************************************************/
@@ -4408,6 +4391,7 @@ static void stl_sc26198intr(struct stlpanel *panelp, unsigned int iobase)
 
 static void stl_sc26198txisr(struct stlport *portp)
 {
+       struct tty_struct *tty;
        unsigned int    ioaddr;
        unsigned char   mr0;
        int             len, stlen;
@@ -4422,8 +4406,11 @@ static void stl_sc26198txisr(struct stlport *portp)
        if ((len == 0) || ((len < STL_TXBUFLOW) &&
            (test_bit(ASYI_TXLOW, &portp->istate) == 0))) {
                set_bit(ASYI_TXLOW, &portp->istate);
-               if (portp->port.tty)
-                       tty_wakeup(portp->port.tty);
+               tty = tty_port_tty_get(&portp->port);
+               if (tty) {
+                       tty_wakeup(tty);
+                       tty_kref_put(tty);
+               }
        }
 
        if (len == 0) {
@@ -4476,7 +4463,7 @@ static void stl_sc26198rxisr(struct stlport *portp, unsigned int iack)
 
        pr_debug("stl_sc26198rxisr(portp=%p,iack=%x)\n", portp, iack);
 
-       tty = portp->port.tty;
+       tty = tty_port_tty_get(&portp->port);
        ioaddr = portp->ioaddr;
        outb(GIBCR, (ioaddr + XP_ADDR));
        len = inb(ioaddr + XP_DATA) + 1;
@@ -4515,6 +4502,7 @@ static void stl_sc26198rxisr(struct stlport *portp, unsigned int iack)
                        stl_sc26198txunflow(portp, tty);
                }
        }
+       tty_kref_put(tty);
 }
 
 /*****************************************************************************/
@@ -4528,7 +4516,7 @@ static void stl_sc26198rxbadch(struct stlport *portp, unsigned char status, char
        struct tty_struct       *tty;
        unsigned int            ioaddr;
 
-       tty = portp->port.tty;
+       tty = tty_port_tty_get(&portp->port);
        ioaddr = portp->ioaddr;
 
        if (status & SR_RXPARITY)
@@ -4566,6 +4554,7 @@ static void stl_sc26198rxbadch(struct stlport *portp, unsigned char status, char
                if (status == 0)
                        portp->stats.rxtotal++;
        }
+       tty_kref_put(tty);
 }
 
 /*****************************************************************************/
index c385206f9db540caa925d615be1c1d4d566482f4..5b8d7a1aa3e64853c21eb524339123a81bd31f3b 100644 (file)
@@ -2504,7 +2504,7 @@ static void __devexit sx_remove_card(struct sx_board *board,
                del_timer(&board->timer);
                if (pdev) {
 #ifdef CONFIG_PCI
-                       pci_iounmap(pdev, board->base);
+                       pci_iounmap(pdev, board->base2);
                        pci_release_region(pdev, IS_CF_BOARD(board) ? 3 : 2);
 #endif
                } else {
@@ -2703,7 +2703,7 @@ static int __devinit sx_pci_probe(struct pci_dev *pdev,
 
        return 0;
 err_unmap:
-       pci_iounmap(pdev, board->base);
+       pci_iounmap(pdev, board->base2);
 err_reg:
        pci_release_region(pdev, reg);
 err_flag:
index ae766d868454406a6d32bbfc7422975d6a9ce550..1fee7034a386f4aa27cf1c5928e8e195f832c0fb 100644 (file)
@@ -954,72 +954,63 @@ EXPORT_SYMBOL_GPL(tpm_store_cancel);
 
 /*
  * Device file system interface to the TPM
+ *
+ * It's assured that the chip will be opened just once,
+ * by the check of is_open variable, which is protected
+ * by driver_lock.
  */
 int tpm_open(struct inode *inode, struct file *file)
 {
-       int rc = 0, minor = iminor(inode);
+       int minor = iminor(inode);
        struct tpm_chip *chip = NULL, *pos;
 
-       lock_kernel();
-       spin_lock(&driver_lock);
-
-       list_for_each_entry(pos, &tpm_chip_list, list) {
+       rcu_read_lock();
+       list_for_each_entry_rcu(pos, &tpm_chip_list, list) {
                if (pos->vendor.miscdev.minor == minor) {
                        chip = pos;
+                       get_device(chip->dev);
                        break;
                }
        }
+       rcu_read_unlock();
 
-       if (chip == NULL) {
-               rc = -ENODEV;
-               goto err_out;
-       }
+       if (!chip)
+               return -ENODEV;
 
-       if (chip->num_opens) {
+       if (test_and_set_bit(0, &chip->is_open)) {
                dev_dbg(chip->dev, "Another process owns this TPM\n");
-               rc = -EBUSY;
-               goto err_out;
+               put_device(chip->dev);
+               return -EBUSY;
        }
 
-       chip->num_opens++;
-       get_device(chip->dev);
-
-       spin_unlock(&driver_lock);
-
        chip->data_buffer = kmalloc(TPM_BUFSIZE * sizeof(u8), GFP_KERNEL);
        if (chip->data_buffer == NULL) {
-               chip->num_opens--;
+               clear_bit(0, &chip->is_open);
                put_device(chip->dev);
-               unlock_kernel();
                return -ENOMEM;
        }
 
        atomic_set(&chip->data_pending, 0);
 
        file->private_data = chip;
-       unlock_kernel();
        return 0;
-
-err_out:
-       spin_unlock(&driver_lock);
-       unlock_kernel();
-       return rc;
 }
 EXPORT_SYMBOL_GPL(tpm_open);
 
+/*
+ * Called on file close
+ */
 int tpm_release(struct inode *inode, struct file *file)
 {
        struct tpm_chip *chip = file->private_data;
 
+       del_singleshot_timer_sync(&chip->user_read_timer);
        flush_scheduled_work();
-       spin_lock(&driver_lock);
        file->private_data = NULL;
-       del_singleshot_timer_sync(&chip->user_read_timer);
        atomic_set(&chip->data_pending, 0);
-       chip->num_opens--;
-       put_device(chip->dev);
        kfree(chip->data_buffer);
-       spin_unlock(&driver_lock);
+       clear_bit(0, &chip->is_open);
+       put_device(chip->dev);
        return 0;
 }
 EXPORT_SYMBOL_GPL(tpm_release);
@@ -1093,13 +1084,11 @@ void tpm_remove_hardware(struct device *dev)
        }
 
        spin_lock(&driver_lock);
-
-       list_del(&chip->list);
-
+       list_del_rcu(&chip->list);
        spin_unlock(&driver_lock);
+       synchronize_rcu();
 
        misc_deregister(&chip->vendor.miscdev);
-
        sysfs_remove_group(&dev->kobj, chip->vendor.attr_group);
        tpm_bios_log_teardown(chip->bios_dir);
 
@@ -1144,25 +1133,33 @@ int tpm_pm_resume(struct device *dev)
 }
 EXPORT_SYMBOL_GPL(tpm_pm_resume);
 
+/* In case vendor provided release function, call it too.*/
+
+void tpm_dev_vendor_release(struct tpm_chip *chip)
+{
+       if (chip->vendor.release)
+               chip->vendor.release(chip->dev);
+
+       clear_bit(chip->dev_num, dev_mask);
+       kfree(chip->vendor.miscdev.name);
+}
+EXPORT_SYMBOL_GPL(tpm_dev_vendor_release);
+
+
 /*
  * Once all references to platform device are down to 0,
  * release all allocated structures.
- * In case vendor provided release function,
- * call it too.
  */
 static void tpm_dev_release(struct device *dev)
 {
        struct tpm_chip *chip = dev_get_drvdata(dev);
 
-       if (chip->vendor.release)
-               chip->vendor.release(dev);
+       tpm_dev_vendor_release(chip);
 
        chip->release(dev);
-
-       clear_bit(chip->dev_num, dev_mask);
-       kfree(chip->vendor.miscdev.name);
        kfree(chip);
 }
+EXPORT_SYMBOL_GPL(tpm_dev_release);
 
 /*
  * Called from tpm_<specific>.c probe function only for devices 
@@ -1171,8 +1168,8 @@ static void tpm_dev_release(struct device *dev)
  * upon errant exit from this function specific probe function should call
  * pci_disable_device
  */
-struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vendor_specific
-                                      *entry)
+struct tpm_chip *tpm_register_hardware(struct device *dev,
+                                       const struct tpm_vendor_specific *entry)
 {
 #define DEVNAME_SIZE 7
 
@@ -1231,21 +1228,20 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vend
                return NULL;
        }
 
-       spin_lock(&driver_lock);
-
-       list_add(&chip->list, &tpm_chip_list);
-
-       spin_unlock(&driver_lock);
-
        if (sysfs_create_group(&dev->kobj, chip->vendor.attr_group)) {
-               list_del(&chip->list);
                misc_deregister(&chip->vendor.miscdev);
                put_device(chip->dev);
+
                return NULL;
        }
 
        chip->bios_dir = tpm_bios_log_setup(devname);
 
+       /* Make chip available */
+       spin_lock(&driver_lock);
+       list_add_rcu(&chip->list, &tpm_chip_list);
+       spin_unlock(&driver_lock);
+
        return chip;
 }
 EXPORT_SYMBOL_GPL(tpm_register_hardware);
index e885148b4cfbd0b177f77b87e6e629511db16983..8e30df4a4388166343af7bfed2aadefdd4f809bc 100644 (file)
@@ -90,7 +90,7 @@ struct tpm_chip {
        struct device *dev;     /* Device stuff */
 
        int dev_num;            /* /dev/tpm# */
-       int num_opens;          /* only one allowed */
+       unsigned long is_open;  /* only one allowed */
        int time_expired;
 
        /* Data passed to and from the tpm via the read/write calls */
@@ -132,6 +132,7 @@ extern struct tpm_chip* tpm_register_hardware(struct device *,
                                 const struct tpm_vendor_specific *);
 extern int tpm_open(struct inode *, struct file *);
 extern int tpm_release(struct inode *, struct file *);
+extern void tpm_dev_vendor_release(struct tpm_chip *);
 extern ssize_t tpm_write(struct file *, const char __user *, size_t,
                         loff_t *);
 extern ssize_t tpm_read(struct file *, char __user *, size_t, loff_t *);
index ed1879c0dd8d1433a0e239631630ce55a971f8b8..717af7ad1bdf5ca28e784b350386182c086f9321 100644 (file)
@@ -630,12 +630,23 @@ static struct pnp_device_id tpm_pnp_tbl[] __devinitdata = {
        {"", 0}                 /* Terminator */
 };
 
+static __devexit void tpm_tis_pnp_remove(struct pnp_dev *dev)
+{
+       struct tpm_chip *chip = pnp_get_drvdata(dev);
+
+       tpm_dev_vendor_release(chip);
+
+       kfree(chip);
+}
+
+
 static struct pnp_driver tis_pnp_driver = {
        .name = "tpm_tis",
        .id_table = tpm_pnp_tbl,
        .probe = tpm_tis_pnp_init,
        .suspend = tpm_tis_pnp_suspend,
        .resume = tpm_tis_pnp_resume,
+       .remove = tpm_tis_pnp_remove,
 };
 
 #define TIS_HID_USR_IDX sizeof(tpm_pnp_tbl)/sizeof(struct pnp_device_id) -2
@@ -683,6 +694,7 @@ static void __exit cleanup_tis(void)
        spin_lock(&tis_lock);
        list_for_each_entry_safe(i, j, &tis_chips, list) {
                chip = to_tpm_chip(i);
+               tpm_remove_hardware(chip->dev);
                iowrite32(~TPM_GLOBAL_INT_ENABLE &
                          ioread32(chip->vendor.iobase +
                                   TPM_INT_ENABLE(chip->vendor.
@@ -694,9 +706,9 @@ static void __exit cleanup_tis(void)
                        free_irq(chip->vendor.irq, chip);
                iounmap(i->iobase);
                list_del(&i->list);
-               tpm_remove_hardware(chip->dev);
        }
        spin_unlock(&tis_lock);
+
        if (force) {
                platform_device_unregister(pdev);
                driver_unregister(&tis_drv);
index 3582f43345a8c1d40397d2284dd2bc11d77a9fd4..5787249934c8b01b1603b38677cf5f55ff5a4ed9 100644 (file)
@@ -93,7 +93,7 @@ static void tty_audit_buf_push(struct task_struct *tsk, uid_t loginuid,
                get_task_comm(name, tsk);
                audit_log_untrustedstring(ab, name);
                audit_log_format(ab, " data=");
-               audit_log_n_untrustedstring(ab, buf->data, buf->valid);
+               audit_log_n_hex(ab, buf->data, buf->valid);
                audit_log_end(ab);
        }
        buf->valid = 0;
diff --git a/drivers/char/tty_buffer.c b/drivers/char/tty_buffer.c
new file mode 100644 (file)
index 0000000..810ee25
--- /dev/null
@@ -0,0 +1,511 @@
+/*
+ * Tty buffer allocation management
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/timer.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/wait.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+
+/**
+ *     tty_buffer_free_all             -       free buffers used by a tty
+ *     @tty: tty to free from
+ *
+ *     Remove all the buffers pending on a tty whether queued with data
+ *     or in the free ring. Must be called when the tty is no longer in use
+ *
+ *     Locking: none
+ */
+
+void tty_buffer_free_all(struct tty_struct *tty)
+{
+       struct tty_buffer *thead;
+       while ((thead = tty->buf.head) != NULL) {
+               tty->buf.head = thead->next;
+               kfree(thead);
+       }
+       while ((thead = tty->buf.free) != NULL) {
+               tty->buf.free = thead->next;
+               kfree(thead);
+       }
+       tty->buf.tail = NULL;
+       tty->buf.memory_used = 0;
+}
+
+/**
+ *     tty_buffer_alloc        -       allocate a tty buffer
+ *     @tty: tty device
+ *     @size: desired size (characters)
+ *
+ *     Allocate a new tty buffer to hold the desired number of characters.
+ *     Return NULL if out of memory or the allocation would exceed the
+ *     per device queue
+ *
+ *     Locking: Caller must hold tty->buf.lock
+ */
+
+static struct tty_buffer *tty_buffer_alloc(struct tty_struct *tty, size_t size)
+{
+       struct tty_buffer *p;
+
+       if (tty->buf.memory_used + size > 65536)
+               return NULL;
+       p = kmalloc(sizeof(struct tty_buffer) + 2 * size, GFP_ATOMIC);
+       if (p == NULL)
+               return NULL;
+       p->used = 0;
+       p->size = size;
+       p->next = NULL;
+       p->commit = 0;
+       p->read = 0;
+       p->char_buf_ptr = (char *)(p->data);
+       p->flag_buf_ptr = (unsigned char *)p->char_buf_ptr + size;
+       tty->buf.memory_used += size;
+       return p;
+}
+
+/**
+ *     tty_buffer_free         -       free a tty buffer
+ *     @tty: tty owning the buffer
+ *     @b: the buffer to free
+ *
+ *     Free a tty buffer, or add it to the free list according to our
+ *     internal strategy
+ *
+ *     Locking: Caller must hold tty->buf.lock
+ */
+
+static void tty_buffer_free(struct tty_struct *tty, struct tty_buffer *b)
+{
+       /* Dumb strategy for now - should keep some stats */
+       tty->buf.memory_used -= b->size;
+       WARN_ON(tty->buf.memory_used < 0);
+
+       if (b->size >= 512)
+               kfree(b);
+       else {
+               b->next = tty->buf.free;
+               tty->buf.free = b;
+       }
+}
+
+/**
+ *     __tty_buffer_flush              -       flush full tty buffers
+ *     @tty: tty to flush
+ *
+ *     flush all the buffers containing receive data. Caller must
+ *     hold the buffer lock and must have ensured no parallel flush to
+ *     ldisc is running.
+ *
+ *     Locking: Caller must hold tty->buf.lock
+ */
+
+static void __tty_buffer_flush(struct tty_struct *tty)
+{
+       struct tty_buffer *thead;
+
+       while ((thead = tty->buf.head) != NULL) {
+               tty->buf.head = thead->next;
+               tty_buffer_free(tty, thead);
+       }
+       tty->buf.tail = NULL;
+}
+
+/**
+ *     tty_buffer_flush                -       flush full tty buffers
+ *     @tty: tty to flush
+ *
+ *     flush all the buffers containing receive data. If the buffer is
+ *     being processed by flush_to_ldisc then we defer the processing
+ *     to that function
+ *
+ *     Locking: none
+ */
+
+void tty_buffer_flush(struct tty_struct *tty)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&tty->buf.lock, flags);
+
+       /* If the data is being pushed to the tty layer then we can't
+          process it here. Instead set a flag and the flush_to_ldisc
+          path will process the flush request before it exits */
+       if (test_bit(TTY_FLUSHING, &tty->flags)) {
+               set_bit(TTY_FLUSHPENDING, &tty->flags);
+               spin_unlock_irqrestore(&tty->buf.lock, flags);
+               wait_event(tty->read_wait,
+                               test_bit(TTY_FLUSHPENDING, &tty->flags) == 0);
+               return;
+       } else
+               __tty_buffer_flush(tty);
+       spin_unlock_irqrestore(&tty->buf.lock, flags);
+}
+
+/**
+ *     tty_buffer_find         -       find a free tty buffer
+ *     @tty: tty owning the buffer
+ *     @size: characters wanted
+ *
+ *     Locate an existing suitable tty buffer or if we are lacking one then
+ *     allocate a new one. We round our buffers off in 256 character chunks
+ *     to get better allocation behaviour.
+ *
+ *     Locking: Caller must hold tty->buf.lock
+ */
+
+static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size)
+{
+       struct tty_buffer **tbh = &tty->buf.free;
+       while ((*tbh) != NULL) {
+               struct tty_buffer *t = *tbh;
+               if (t->size >= size) {
+                       *tbh = t->next;
+                       t->next = NULL;
+                       t->used = 0;
+                       t->commit = 0;
+                       t->read = 0;
+                       tty->buf.memory_used += t->size;
+                       return t;
+               }
+               tbh = &((*tbh)->next);
+       }
+       /* Round the buffer size out */
+       size = (size + 0xFF) & ~0xFF;
+       return tty_buffer_alloc(tty, size);
+       /* Should possibly check if this fails for the largest buffer we
+          have queued and recycle that ? */
+}
+
+/**
+ *     tty_buffer_request_room         -       grow tty buffer if needed
+ *     @tty: tty structure
+ *     @size: size desired
+ *
+ *     Make at least size bytes of linear space available for the tty
+ *     buffer. If we fail return the size we managed to find.
+ *
+ *     Locking: Takes tty->buf.lock
+ */
+int tty_buffer_request_room(struct tty_struct *tty, size_t size)
+{
+       struct tty_buffer *b, *n;
+       int left;
+       unsigned long flags;
+
+       spin_lock_irqsave(&tty->buf.lock, flags);
+
+       /* OPTIMISATION: We could keep a per tty "zero" sized buffer to
+          remove this conditional if its worth it. This would be invisible
+          to the callers */
+       if ((b = tty->buf.tail) != NULL)
+               left = b->size - b->used;
+       else
+               left = 0;
+
+       if (left < size) {
+               /* This is the slow path - looking for new buffers to use */
+               if ((n = tty_buffer_find(tty, size)) != NULL) {
+                       if (b != NULL) {
+                               b->next = n;
+                               b->commit = b->used;
+                       } else
+                               tty->buf.head = n;
+                       tty->buf.tail = n;
+               } else
+                       size = left;
+       }
+
+       spin_unlock_irqrestore(&tty->buf.lock, flags);
+       return size;
+}
+EXPORT_SYMBOL_GPL(tty_buffer_request_room);
+
+/**
+ *     tty_insert_flip_string  -       Add characters to the tty buffer
+ *     @tty: tty structure
+ *     @chars: characters
+ *     @size: size
+ *
+ *     Queue a series of bytes to the tty buffering. All the characters
+ *     passed are marked as without error. Returns the number added.
+ *
+ *     Locking: Called functions may take tty->buf.lock
+ */
+
+int tty_insert_flip_string(struct tty_struct *tty, const unsigned char *chars,
+                               size_t size)
+{
+       int copied = 0;
+       do {
+               int space = tty_buffer_request_room(tty, size - copied);
+               struct tty_buffer *tb = tty->buf.tail;
+               /* If there is no space then tb may be NULL */
+               if (unlikely(space == 0))
+                       break;
+               memcpy(tb->char_buf_ptr + tb->used, chars, space);
+               memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space);
+               tb->used += space;
+               copied += space;
+               chars += space;
+               /* There is a small chance that we need to split the data over
+                  several buffers. If this is the case we must loop */
+       } while (unlikely(size > copied));
+       return copied;
+}
+EXPORT_SYMBOL(tty_insert_flip_string);
+
+/**
+ *     tty_insert_flip_string_flags    -       Add characters to the tty buffer
+ *     @tty: tty structure
+ *     @chars: characters
+ *     @flags: flag bytes
+ *     @size: size
+ *
+ *     Queue a series of bytes to the tty buffering. For each character
+ *     the flags array indicates the status of the character. Returns the
+ *     number added.
+ *
+ *     Locking: Called functions may take tty->buf.lock
+ */
+
+int tty_insert_flip_string_flags(struct tty_struct *tty,
+               const unsigned char *chars, const char *flags, size_t size)
+{
+       int copied = 0;
+       do {
+               int space = tty_buffer_request_room(tty, size - copied);
+               struct tty_buffer *tb = tty->buf.tail;
+               /* If there is no space then tb may be NULL */
+               if (unlikely(space == 0))
+                       break;
+               memcpy(tb->char_buf_ptr + tb->used, chars, space);
+               memcpy(tb->flag_buf_ptr + tb->used, flags, space);
+               tb->used += space;
+               copied += space;
+               chars += space;
+               flags += space;
+               /* There is a small chance that we need to split the data over
+                  several buffers. If this is the case we must loop */
+       } while (unlikely(size > copied));
+       return copied;
+}
+EXPORT_SYMBOL(tty_insert_flip_string_flags);
+
+/**
+ *     tty_schedule_flip       -       push characters to ldisc
+ *     @tty: tty to push from
+ *
+ *     Takes any pending buffers and transfers their ownership to the
+ *     ldisc side of the queue. It then schedules those characters for
+ *     processing by the line discipline.
+ *
+ *     Locking: Takes tty->buf.lock
+ */
+
+void tty_schedule_flip(struct tty_struct *tty)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&tty->buf.lock, flags);
+       if (tty->buf.tail != NULL)
+               tty->buf.tail->commit = tty->buf.tail->used;
+       spin_unlock_irqrestore(&tty->buf.lock, flags);
+       schedule_delayed_work(&tty->buf.work, 1);
+}
+EXPORT_SYMBOL(tty_schedule_flip);
+
+/**
+ *     tty_prepare_flip_string         -       make room for characters
+ *     @tty: tty
+ *     @chars: return pointer for character write area
+ *     @size: desired size
+ *
+ *     Prepare a block of space in the buffer for data. Returns the length
+ *     available and buffer pointer to the space which is now allocated and
+ *     accounted for as ready for normal characters. This is used for drivers
+ *     that need their own block copy routines into the buffer. There is no
+ *     guarantee the buffer is a DMA target!
+ *
+ *     Locking: May call functions taking tty->buf.lock
+ */
+
+int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars,
+                                                               size_t size)
+{
+       int space = tty_buffer_request_room(tty, size);
+       if (likely(space)) {
+               struct tty_buffer *tb = tty->buf.tail;
+               *chars = tb->char_buf_ptr + tb->used;
+               memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space);
+               tb->used += space;
+       }
+       return space;
+}
+EXPORT_SYMBOL_GPL(tty_prepare_flip_string);
+
+/**
+ *     tty_prepare_flip_string_flags   -       make room for characters
+ *     @tty: tty
+ *     @chars: return pointer for character write area
+ *     @flags: return pointer for status flag write area
+ *     @size: desired size
+ *
+ *     Prepare a block of space in the buffer for data. Returns the length
+ *     available and buffer pointer to the space which is now allocated and
+ *     accounted for as ready for characters. This is used for drivers
+ *     that need their own block copy routines into the buffer. There is no
+ *     guarantee the buffer is a DMA target!
+ *
+ *     Locking: May call functions taking tty->buf.lock
+ */
+
+int tty_prepare_flip_string_flags(struct tty_struct *tty,
+                       unsigned char **chars, char **flags, size_t size)
+{
+       int space = tty_buffer_request_room(tty, size);
+       if (likely(space)) {
+               struct tty_buffer *tb = tty->buf.tail;
+               *chars = tb->char_buf_ptr + tb->used;
+               *flags = tb->flag_buf_ptr + tb->used;
+               tb->used += space;
+       }
+       return space;
+}
+EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags);
+
+
+
+/**
+ *     flush_to_ldisc
+ *     @work: tty structure passed from work queue.
+ *
+ *     This routine is called out of the software interrupt to flush data
+ *     from the buffer chain to the line discipline.
+ *
+ *     Locking: holds tty->buf.lock to guard buffer list. Drops the lock
+ *     while invoking the line discipline receive_buf method. The
+ *     receive_buf method is single threaded for each tty instance.
+ */
+
+static void flush_to_ldisc(struct work_struct *work)
+{
+       struct tty_struct *tty =
+               container_of(work, struct tty_struct, buf.work.work);
+       unsigned long   flags;
+       struct tty_ldisc *disc;
+       struct tty_buffer *tbuf, *head;
+       char *char_buf;
+       unsigned char *flag_buf;
+
+       disc = tty_ldisc_ref(tty);
+       if (disc == NULL)       /*  !TTY_LDISC */
+               return;
+
+       spin_lock_irqsave(&tty->buf.lock, flags);
+       /* So we know a flush is running */
+       set_bit(TTY_FLUSHING, &tty->flags);
+       head = tty->buf.head;
+       if (head != NULL) {
+               tty->buf.head = NULL;
+               for (;;) {
+                       int count = head->commit - head->read;
+                       if (!count) {
+                               if (head->next == NULL)
+                                       break;
+                               tbuf = head;
+                               head = head->next;
+                               tty_buffer_free(tty, tbuf);
+                               continue;
+                       }
+                       /* Ldisc or user is trying to flush the buffers
+                          we are feeding to the ldisc, stop feeding the
+                          line discipline as we want to empty the queue */
+                       if (test_bit(TTY_FLUSHPENDING, &tty->flags))
+                               break;
+                       if (!tty->receive_room) {
+                               schedule_delayed_work(&tty->buf.work, 1);
+                               break;
+                       }
+                       if (count > tty->receive_room)
+                               count = tty->receive_room;
+                       char_buf = head->char_buf_ptr + head->read;
+                       flag_buf = head->flag_buf_ptr + head->read;
+                       head->read += count;
+                       spin_unlock_irqrestore(&tty->buf.lock, flags);
+                       disc->ops->receive_buf(tty, char_buf,
+                                                       flag_buf, count);
+                       spin_lock_irqsave(&tty->buf.lock, flags);
+               }
+               /* Restore the queue head */
+               tty->buf.head = head;
+       }
+       /* We may have a deferred request to flush the input buffer,
+          if so pull the chain under the lock and empty the queue */
+       if (test_bit(TTY_FLUSHPENDING, &tty->flags)) {
+               __tty_buffer_flush(tty);
+               clear_bit(TTY_FLUSHPENDING, &tty->flags);
+               wake_up(&tty->read_wait);
+       }
+       clear_bit(TTY_FLUSHING, &tty->flags);
+       spin_unlock_irqrestore(&tty->buf.lock, flags);
+
+       tty_ldisc_deref(disc);
+}
+
+/**
+ *     tty_flip_buffer_push    -       terminal
+ *     @tty: tty to push
+ *
+ *     Queue a push of the terminal flip buffers to the line discipline. This
+ *     function must not be called from IRQ context if tty->low_latency is set.
+ *
+ *     In the event of the queue being busy for flipping the work will be
+ *     held off and retried later.
+ *
+ *     Locking: tty buffer lock. Driver locks in low latency mode.
+ */
+
+void tty_flip_buffer_push(struct tty_struct *tty)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&tty->buf.lock, flags);
+       if (tty->buf.tail != NULL)
+               tty->buf.tail->commit = tty->buf.tail->used;
+       spin_unlock_irqrestore(&tty->buf.lock, flags);
+
+       if (tty->low_latency)
+               flush_to_ldisc(&tty->buf.work.work);
+       else
+               schedule_delayed_work(&tty->buf.work, 1);
+}
+EXPORT_SYMBOL(tty_flip_buffer_push);
+
+/**
+ *     tty_buffer_init         -       prepare a tty buffer structure
+ *     @tty: tty to initialise
+ *
+ *     Set up the initial state of the buffer management for a tty device.
+ *     Must be called before the other tty buffer functions are used.
+ *
+ *     Locking: none
+ */
+
+void tty_buffer_init(struct tty_struct *tty)
+{
+       spin_lock_init(&tty->buf.lock);
+       tty->buf.head = NULL;
+       tty->buf.tail = NULL;
+       tty->buf.free = NULL;
+       tty->buf.memory_used = 0;
+       INIT_DELAYED_WORK(&tty->buf.work, flush_to_ldisc);
+}
+
index e4dce87095410f8f648137ecb992927a6630c483..7053d6333692d7bd8fcd112a4dfc8bac783ccbc0 100644 (file)
@@ -49,7 +49,7 @@
  * implement CONFIG_VT and generalize console device interface.
  *     -- Marko Kohtala <Marko.Kohtala@hut.fi>, March 97
  *
- * Rewrote init_dev and release_dev to eliminate races.
+ * Rewrote tty_init_dev and tty_release_dev to eliminate races.
  *     -- Bill Hawes <whawes@star.net>, June 97
  *
  * Added devfs support.
@@ -136,13 +136,6 @@ LIST_HEAD(tty_drivers);                    /* linked list of tty drivers */
 DEFINE_MUTEX(tty_mutex);
 EXPORT_SYMBOL(tty_mutex);
 
-#ifdef CONFIG_UNIX98_PTYS
-extern struct tty_driver *ptm_driver;  /* Unix98 pty masters; for /dev/ptmx */
-static int ptmx_open(struct inode *, struct file *);
-#endif
-
-static void initialize_tty_struct(struct tty_struct *tty);
-
 static ssize_t tty_read(struct file *, char __user *, size_t, loff_t *);
 static ssize_t tty_write(struct file *, const char __user *, size_t, loff_t *);
 ssize_t redirected_tty_write(struct file *, const char __user *,
@@ -171,13 +164,11 @@ static void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty);
  *     Locking: none
  */
 
-static struct tty_struct *alloc_tty_struct(void)
+struct tty_struct *alloc_tty_struct(void)
 {
        return kzalloc(sizeof(struct tty_struct), GFP_KERNEL);
 }
 
-static void tty_buffer_free_all(struct tty_struct *);
-
 /**
  *     free_tty_struct         -       free a disused tty
  *     @tty: tty struct to free
@@ -187,7 +178,7 @@ static void tty_buffer_free_all(struct tty_struct *);
  *     Locking: none. Must be called after tty is definitely unused
  */
 
-static inline void free_tty_struct(struct tty_struct *tty)
+void free_tty_struct(struct tty_struct *tty)
 {
        kfree(tty->write_buf);
        tty_buffer_free_all(tty);
@@ -263,398 +254,6 @@ static int check_tty_count(struct tty_struct *tty, const char *routine)
        return 0;
 }
 
-/*
- * Tty buffer allocation management
- */
-
-/**
- *     tty_buffer_free_all             -       free buffers used by a tty
- *     @tty: tty to free from
- *
- *     Remove all the buffers pending on a tty whether queued with data
- *     or in the free ring. Must be called when the tty is no longer in use
- *
- *     Locking: none
- */
-
-static void tty_buffer_free_all(struct tty_struct *tty)
-{
-       struct tty_buffer *thead;
-       while ((thead = tty->buf.head) != NULL) {
-               tty->buf.head = thead->next;
-               kfree(thead);
-       }
-       while ((thead = tty->buf.free) != NULL) {
-               tty->buf.free = thead->next;
-               kfree(thead);
-       }
-       tty->buf.tail = NULL;
-       tty->buf.memory_used = 0;
-}
-
-/**
- *     tty_buffer_init         -       prepare a tty buffer structure
- *     @tty: tty to initialise
- *
- *     Set up the initial state of the buffer management for a tty device.
- *     Must be called before the other tty buffer functions are used.
- *
- *     Locking: none
- */
-
-static void tty_buffer_init(struct tty_struct *tty)
-{
-       spin_lock_init(&tty->buf.lock);
-       tty->buf.head = NULL;
-       tty->buf.tail = NULL;
-       tty->buf.free = NULL;
-       tty->buf.memory_used = 0;
-}
-
-/**
- *     tty_buffer_alloc        -       allocate a tty buffer
- *     @tty: tty device
- *     @size: desired size (characters)
- *
- *     Allocate a new tty buffer to hold the desired number of characters.
- *     Return NULL if out of memory or the allocation would exceed the
- *     per device queue
- *
- *     Locking: Caller must hold tty->buf.lock
- */
-
-static struct tty_buffer *tty_buffer_alloc(struct tty_struct *tty, size_t size)
-{
-       struct tty_buffer *p;
-
-       if (tty->buf.memory_used + size > 65536)
-               return NULL;
-       p = kmalloc(sizeof(struct tty_buffer) + 2 * size, GFP_ATOMIC);
-       if (p == NULL)
-               return NULL;
-       p->used = 0;
-       p->size = size;
-       p->next = NULL;
-       p->commit = 0;
-       p->read = 0;
-       p->char_buf_ptr = (char *)(p->data);
-       p->flag_buf_ptr = (unsigned char *)p->char_buf_ptr + size;
-       tty->buf.memory_used += size;
-       return p;
-}
-
-/**
- *     tty_buffer_free         -       free a tty buffer
- *     @tty: tty owning the buffer
- *     @b: the buffer to free
- *
- *     Free a tty buffer, or add it to the free list according to our
- *     internal strategy
- *
- *     Locking: Caller must hold tty->buf.lock
- */
-
-static void tty_buffer_free(struct tty_struct *tty, struct tty_buffer *b)
-{
-       /* Dumb strategy for now - should keep some stats */
-       tty->buf.memory_used -= b->size;
-       WARN_ON(tty->buf.memory_used < 0);
-
-       if (b->size >= 512)
-               kfree(b);
-       else {
-               b->next = tty->buf.free;
-               tty->buf.free = b;
-       }
-}
-
-/**
- *     __tty_buffer_flush              -       flush full tty buffers
- *     @tty: tty to flush
- *
- *     flush all the buffers containing receive data. Caller must
- *     hold the buffer lock and must have ensured no parallel flush to
- *     ldisc is running.
- *
- *     Locking: Caller must hold tty->buf.lock
- */
-
-static void __tty_buffer_flush(struct tty_struct *tty)
-{
-       struct tty_buffer *thead;
-
-       while ((thead = tty->buf.head) != NULL) {
-               tty->buf.head = thead->next;
-               tty_buffer_free(tty, thead);
-       }
-       tty->buf.tail = NULL;
-}
-
-/**
- *     tty_buffer_flush                -       flush full tty buffers
- *     @tty: tty to flush
- *
- *     flush all the buffers containing receive data. If the buffer is
- *     being processed by flush_to_ldisc then we defer the processing
- *     to that function
- *
- *     Locking: none
- */
-
-static void tty_buffer_flush(struct tty_struct *tty)
-{
-       unsigned long flags;
-       spin_lock_irqsave(&tty->buf.lock, flags);
-
-       /* If the data is being pushed to the tty layer then we can't
-          process it here. Instead set a flag and the flush_to_ldisc
-          path will process the flush request before it exits */
-       if (test_bit(TTY_FLUSHING, &tty->flags)) {
-               set_bit(TTY_FLUSHPENDING, &tty->flags);
-               spin_unlock_irqrestore(&tty->buf.lock, flags);
-               wait_event(tty->read_wait,
-                               test_bit(TTY_FLUSHPENDING, &tty->flags) == 0);
-               return;
-       } else
-               __tty_buffer_flush(tty);
-       spin_unlock_irqrestore(&tty->buf.lock, flags);
-}
-
-/**
- *     tty_buffer_find         -       find a free tty buffer
- *     @tty: tty owning the buffer
- *     @size: characters wanted
- *
- *     Locate an existing suitable tty buffer or if we are lacking one then
- *     allocate a new one. We round our buffers off in 256 character chunks
- *     to get better allocation behaviour.
- *
- *     Locking: Caller must hold tty->buf.lock
- */
-
-static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size)
-{
-       struct tty_buffer **tbh = &tty->buf.free;
-       while ((*tbh) != NULL) {
-               struct tty_buffer *t = *tbh;
-               if (t->size >= size) {
-                       *tbh = t->next;
-                       t->next = NULL;
-                       t->used = 0;
-                       t->commit = 0;
-                       t->read = 0;
-                       tty->buf.memory_used += t->size;
-                       return t;
-               }
-               tbh = &((*tbh)->next);
-       }
-       /* Round the buffer size out */
-       size = (size + 0xFF) & ~0xFF;
-       return tty_buffer_alloc(tty, size);
-       /* Should possibly check if this fails for the largest buffer we
-          have queued and recycle that ? */
-}
-
-/**
- *     tty_buffer_request_room         -       grow tty buffer if needed
- *     @tty: tty structure
- *     @size: size desired
- *
- *     Make at least size bytes of linear space available for the tty
- *     buffer. If we fail return the size we managed to find.
- *
- *     Locking: Takes tty->buf.lock
- */
-int tty_buffer_request_room(struct tty_struct *tty, size_t size)
-{
-       struct tty_buffer *b, *n;
-       int left;
-       unsigned long flags;
-
-       spin_lock_irqsave(&tty->buf.lock, flags);
-
-       /* OPTIMISATION: We could keep a per tty "zero" sized buffer to
-          remove this conditional if its worth it. This would be invisible
-          to the callers */
-       if ((b = tty->buf.tail) != NULL)
-               left = b->size - b->used;
-       else
-               left = 0;
-
-       if (left < size) {
-               /* This is the slow path - looking for new buffers to use */
-               if ((n = tty_buffer_find(tty, size)) != NULL) {
-                       if (b != NULL) {
-                               b->next = n;
-                               b->commit = b->used;
-                       } else
-                               tty->buf.head = n;
-                       tty->buf.tail = n;
-               } else
-                       size = left;
-       }
-
-       spin_unlock_irqrestore(&tty->buf.lock, flags);
-       return size;
-}
-EXPORT_SYMBOL_GPL(tty_buffer_request_room);
-
-/**
- *     tty_insert_flip_string  -       Add characters to the tty buffer
- *     @tty: tty structure
- *     @chars: characters
- *     @size: size
- *
- *     Queue a series of bytes to the tty buffering. All the characters
- *     passed are marked as without error. Returns the number added.
- *
- *     Locking: Called functions may take tty->buf.lock
- */
-
-int tty_insert_flip_string(struct tty_struct *tty, const unsigned char *chars,
-                               size_t size)
-{
-       int copied = 0;
-       do {
-               int space = tty_buffer_request_room(tty, size - copied);
-               struct tty_buffer *tb = tty->buf.tail;
-               /* If there is no space then tb may be NULL */
-               if (unlikely(space == 0))
-                       break;
-               memcpy(tb->char_buf_ptr + tb->used, chars, space);
-               memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space);
-               tb->used += space;
-               copied += space;
-               chars += space;
-               /* There is a small chance that we need to split the data over
-                  several buffers. If this is the case we must loop */
-       } while (unlikely(size > copied));
-       return copied;
-}
-EXPORT_SYMBOL(tty_insert_flip_string);
-
-/**
- *     tty_insert_flip_string_flags    -       Add characters to the tty buffer
- *     @tty: tty structure
- *     @chars: characters
- *     @flags: flag bytes
- *     @size: size
- *
- *     Queue a series of bytes to the tty buffering. For each character
- *     the flags array indicates the status of the character. Returns the
- *     number added.
- *
- *     Locking: Called functions may take tty->buf.lock
- */
-
-int tty_insert_flip_string_flags(struct tty_struct *tty,
-               const unsigned char *chars, const char *flags, size_t size)
-{
-       int copied = 0;
-       do {
-               int space = tty_buffer_request_room(tty, size - copied);
-               struct tty_buffer *tb = tty->buf.tail;
-               /* If there is no space then tb may be NULL */
-               if (unlikely(space == 0))
-                       break;
-               memcpy(tb->char_buf_ptr + tb->used, chars, space);
-               memcpy(tb->flag_buf_ptr + tb->used, flags, space);
-               tb->used += space;
-               copied += space;
-               chars += space;
-               flags += space;
-               /* There is a small chance that we need to split the data over
-                  several buffers. If this is the case we must loop */
-       } while (unlikely(size > copied));
-       return copied;
-}
-EXPORT_SYMBOL(tty_insert_flip_string_flags);
-
-/**
- *     tty_schedule_flip       -       push characters to ldisc
- *     @tty: tty to push from
- *
- *     Takes any pending buffers and transfers their ownership to the
- *     ldisc side of the queue. It then schedules those characters for
- *     processing by the line discipline.
- *
- *     Locking: Takes tty->buf.lock
- */
-
-void tty_schedule_flip(struct tty_struct *tty)
-{
-       unsigned long flags;
-       spin_lock_irqsave(&tty->buf.lock, flags);
-       if (tty->buf.tail != NULL)
-               tty->buf.tail->commit = tty->buf.tail->used;
-       spin_unlock_irqrestore(&tty->buf.lock, flags);
-       schedule_delayed_work(&tty->buf.work, 1);
-}
-EXPORT_SYMBOL(tty_schedule_flip);
-
-/**
- *     tty_prepare_flip_string         -       make room for characters
- *     @tty: tty
- *     @chars: return pointer for character write area
- *     @size: desired size
- *
- *     Prepare a block of space in the buffer for data. Returns the length
- *     available and buffer pointer to the space which is now allocated and
- *     accounted for as ready for normal characters. This is used for drivers
- *     that need their own block copy routines into the buffer. There is no
- *     guarantee the buffer is a DMA target!
- *
- *     Locking: May call functions taking tty->buf.lock
- */
-
-int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars,
-                                                               size_t size)
-{
-       int space = tty_buffer_request_room(tty, size);
-       if (likely(space)) {
-               struct tty_buffer *tb = tty->buf.tail;
-               *chars = tb->char_buf_ptr + tb->used;
-               memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space);
-               tb->used += space;
-       }
-       return space;
-}
-
-EXPORT_SYMBOL_GPL(tty_prepare_flip_string);
-
-/**
- *     tty_prepare_flip_string_flags   -       make room for characters
- *     @tty: tty
- *     @chars: return pointer for character write area
- *     @flags: return pointer for status flag write area
- *     @size: desired size
- *
- *     Prepare a block of space in the buffer for data. Returns the length
- *     available and buffer pointer to the space which is now allocated and
- *     accounted for as ready for characters. This is used for drivers
- *     that need their own block copy routines into the buffer. There is no
- *     guarantee the buffer is a DMA target!
- *
- *     Locking: May call functions taking tty->buf.lock
- */
-
-int tty_prepare_flip_string_flags(struct tty_struct *tty,
-                       unsigned char **chars, char **flags, size_t size)
-{
-       int space = tty_buffer_request_room(tty, size);
-       if (likely(space)) {
-               struct tty_buffer *tb = tty->buf.tail;
-               *chars = tb->char_buf_ptr + tb->used;
-               *flags = tb->flag_buf_ptr + tb->used;
-               tb->used += space;
-       }
-       return space;
-}
-
-EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags);
-
-
-
 /**
  *     get_tty_driver          -       find device of a tty
  *     @dev_t: device identifier
@@ -675,7 +274,7 @@ static struct tty_driver *get_tty_driver(dev_t device, int *index)
                if (device < base || device >= base + p->num)
                        continue;
                *index = device - base;
-               return p;
+               return tty_driver_kref_get(p);
        }
        return NULL;
 }
@@ -719,7 +318,7 @@ struct tty_driver *tty_find_polling_driver(char *name, int *line)
 
                if (tty_line >= 0 && tty_line <= p->num && p->ops &&
                    p->ops->poll_init && !p->ops->poll_init(p, tty_line, str)) {
-                       res = p;
+                       res = tty_driver_kref_get(p);
                        *line = tty_line;
                        break;
                }
@@ -819,20 +418,6 @@ static const struct file_operations tty_fops = {
        .fasync         = tty_fasync,
 };
 
-#ifdef CONFIG_UNIX98_PTYS
-static const struct file_operations ptmx_fops = {
-       .llseek         = no_llseek,
-       .read           = tty_read,
-       .write          = tty_write,
-       .poll           = tty_poll,
-       .unlocked_ioctl = tty_ioctl,
-       .compat_ioctl   = tty_compat_ioctl,
-       .open           = ptmx_open,
-       .release        = tty_release,
-       .fasync         = tty_fasync,
-};
-#endif
-
 static const struct file_operations console_fops = {
        .llseek         = no_llseek,
        .read           = tty_read,
@@ -953,6 +538,7 @@ static void do_tty_hangup(struct work_struct *work)
        struct tty_ldisc *ld;
        int    closecount = 0, n;
        unsigned long flags;
+       int refs = 0;
 
        if (!tty)
                return;
@@ -1019,8 +605,12 @@ static void do_tty_hangup(struct work_struct *work)
        if (tty->session) {
                do_each_pid_task(tty->session, PIDTYPE_SID, p) {
                        spin_lock_irq(&p->sighand->siglock);
-                       if (p->signal->tty == tty)
+                       if (p->signal->tty == tty) {
                                p->signal->tty = NULL;
+                               /* We defer the dereferences outside fo
+                                  the tasklist lock */
+                               refs++;
+                       }
                        if (!p->signal->leader) {
                                spin_unlock_irq(&p->sighand->siglock);
                                continue;
@@ -1046,6 +636,10 @@ static void do_tty_hangup(struct work_struct *work)
        tty->ctrl_status = 0;
        spin_unlock_irqrestore(&tty->ctrl_lock, flags);
 
+       /* Account for the p->signal references we killed */
+       while (refs--)
+               tty_kref_put(tty);
+
        /*
         * If one of the devices matches a console pointer, we
         * cannot just call hangup() because that will cause
@@ -1114,6 +708,23 @@ void tty_vhangup(struct tty_struct *tty)
 
 EXPORT_SYMBOL(tty_vhangup);
 
+/**
+ *     tty_vhangup_self        -       process vhangup for own ctty
+ *
+ *     Perform a vhangup on the current controlling tty
+ */
+
+void tty_vhangup_self(void)
+{
+       struct tty_struct *tty;
+
+       tty = get_current_tty();
+       if (tty) {
+               tty_vhangup(tty);
+               tty_kref_put(tty);
+       }
+}
+
 /**
  *     tty_hung_up_p           -       was tty hung up
  *     @filp: file pointer of tty
@@ -1167,16 +778,14 @@ void disassociate_ctty(int on_exit)
        struct pid *tty_pgrp = NULL;
 
 
-       mutex_lock(&tty_mutex);
        tty = get_current_tty();
        if (tty) {
                tty_pgrp = get_pid(tty->pgrp);
                lock_kernel();
-               mutex_unlock(&tty_mutex);
-               /* XXX: here we race, there is nothing protecting tty */
                if (on_exit && tty->driver->type != TTY_DRIVER_TYPE_PTY)
                        tty_vhangup(tty);
                unlock_kernel();
+               tty_kref_put(tty);
        } else if (on_exit) {
                struct pid *old_pgrp;
                spin_lock_irq(&current->sighand->siglock);
@@ -1188,7 +797,6 @@ void disassociate_ctty(int on_exit)
                        kill_pgrp(old_pgrp, SIGCONT, on_exit);
                        put_pid(old_pgrp);
                }
-               mutex_unlock(&tty_mutex);
                return;
        }
        if (tty_pgrp) {
@@ -1203,8 +811,6 @@ void disassociate_ctty(int on_exit)
        current->signal->tty_old_pgrp = NULL;
        spin_unlock_irq(&current->sighand->siglock);
 
-       mutex_lock(&tty_mutex);
-       /* It is possible that do_tty_hangup has free'd this tty */
        tty = get_current_tty();
        if (tty) {
                unsigned long flags;
@@ -1214,13 +820,13 @@ void disassociate_ctty(int on_exit)
                tty->session = NULL;
                tty->pgrp = NULL;
                spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+               tty_kref_put(tty);
        } else {
 #ifdef TTY_DEBUG_HANGUP
                printk(KERN_DEBUG "error attempted to write to tty [0x%p]"
                       " = NULL", tty);
 #endif
        }
-       mutex_unlock(&tty_mutex);
 
        /* Now clear signal->tty under the lock */
        read_lock(&tasklist_lock);
@@ -1420,19 +1026,19 @@ static inline ssize_t do_tty_write(
 
        /* write_buf/write_cnt is protected by the atomic_write_lock mutex */
        if (tty->write_cnt < chunk) {
-               unsigned char *buf;
+               unsigned char *buf_chunk;
 
                if (chunk < 1024)
                        chunk = 1024;
 
-               buf = kmalloc(chunk, GFP_KERNEL);
-               if (!buf) {
+               buf_chunk = kmalloc(chunk, GFP_KERNEL);
+               if (!buf_chunk) {
                        ret = -ENOMEM;
                        goto out;
                }
                kfree(tty->write_buf);
                tty->write_cnt = chunk;
-               tty->write_buf = buf;
+               tty->write_buf = buf_chunk;
        }
 
        /* Do the write .. */
@@ -1466,6 +1072,31 @@ out:
        return ret;
 }
 
+/**
+ * tty_write_message - write a message to a certain tty, not just the console.
+ * @tty: the destination tty_struct
+ * @msg: the message to write
+ *
+ * This is used for messages that need to be redirected to a specific tty.
+ * We don't put it into the syslog queue right now maybe in the future if
+ * really needed.
+ *
+ * We must still hold the BKL and test the CLOSING flag for the moment.
+ */
+
+void tty_write_message(struct tty_struct *tty, char *msg)
+{
+       lock_kernel();
+       if (tty) {
+               mutex_lock(&tty->atomic_write_lock);
+               if (tty->ops->write && !test_bit(TTY_CLOSING, &tty->flags))
+                       tty->ops->write(tty, msg, strlen(msg));
+               tty_write_unlock(tty);
+       }
+       unlock_kernel();
+       return;
+}
+
 
 /**
  *     tty_write               -       write method for tty device file
@@ -1533,42 +1164,6 @@ ssize_t redirected_tty_write(struct file *file, const char __user *buf,
        return tty_write(file, buf, count, ppos);
 }
 
-void tty_port_init(struct tty_port *port)
-{
-       memset(port, 0, sizeof(*port));
-       init_waitqueue_head(&port->open_wait);
-       init_waitqueue_head(&port->close_wait);
-       mutex_init(&port->mutex);
-       port->close_delay = (50 * HZ) / 100;
-       port->closing_wait = (3000 * HZ) / 100;
-}
-EXPORT_SYMBOL(tty_port_init);
-
-int tty_port_alloc_xmit_buf(struct tty_port *port)
-{
-       /* We may sleep in get_zeroed_page() */
-       mutex_lock(&port->mutex);
-       if (port->xmit_buf == NULL)
-               port->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL);
-       mutex_unlock(&port->mutex);
-       if (port->xmit_buf == NULL)
-               return -ENOMEM;
-       return 0;
-}
-EXPORT_SYMBOL(tty_port_alloc_xmit_buf);
-
-void tty_port_free_xmit_buf(struct tty_port *port)
-{
-       mutex_lock(&port->mutex);
-       if (port->xmit_buf != NULL) {
-               free_page((unsigned long)port->xmit_buf);
-               port->xmit_buf = NULL;
-       }
-       mutex_unlock(&port->mutex);
-}
-EXPORT_SYMBOL(tty_port_free_xmit_buf);
-
-
 static char ptychar[] = "pqrstuvwxyzabcde";
 
 /**
@@ -1592,7 +1187,7 @@ static void pty_line_name(struct tty_driver *driver, int index, char *p)
 }
 
 /**
- *     pty_line_name   -       generate name for a tty
+ *     tty_line_name   -       generate name for a tty
  *     @driver: the tty driver in use
  *     @index: the minor number
  *     @p: output buffer of at least 7 bytes
@@ -1608,10 +1203,148 @@ static void tty_line_name(struct tty_driver *driver, int index, char *p)
 }
 
 /**
- *     init_dev                -       initialise a tty device
+ *     tty_driver_lookup_tty() - find an existing tty, if any
+ *     @driver: the driver for the tty
+ *     @idx:    the minor number
+ *
+ *     Return the tty, if found or ERR_PTR() otherwise.
+ *
+ *     Locking: tty_mutex must be held. If tty is found, the mutex must
+ *     be held until the 'fast-open' is also done. Will change once we
+ *     have refcounting in the driver and per driver locking
+ */
+struct tty_struct *tty_driver_lookup_tty(struct tty_driver *driver,
+               struct inode *inode, int idx)
+{
+       struct tty_struct *tty;
+
+       if (driver->ops->lookup)
+               return driver->ops->lookup(driver, inode, idx);
+
+       tty = driver->ttys[idx];
+       return tty;
+}
+
+/**
+ *     tty_init_termios        -  helper for termios setup
+ *     @tty: the tty to set up
+ *
+ *     Initialise the termios structures for this tty. Thus runs under
+ *     the tty_mutex currently so we can be relaxed about ordering.
+ */
+
+int tty_init_termios(struct tty_struct *tty)
+{
+       struct ktermios *tp;
+       int idx = tty->index;
+
+       tp = tty->driver->termios[idx];
+       if (tp == NULL) {
+               tp = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL);
+               if (tp == NULL)
+                       return -ENOMEM;
+               memcpy(tp, &tty->driver->init_termios,
+                                               sizeof(struct ktermios));
+               tty->driver->termios[idx] = tp;
+       }
+       tty->termios = tp;
+       tty->termios_locked = tp + 1;
+
+       /* Compatibility until drivers always set this */
+       tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios);
+       tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios);
+       return 0;
+}
+
+/**
+ *     tty_driver_install_tty() - install a tty entry in the driver
+ *     @driver: the driver for the tty
+ *     @tty: the tty
+ *
+ *     Install a tty object into the driver tables. The tty->index field
+ *     will be set by the time this is called. This method is responsible
+ *     for ensuring any need additional structures are allocated and
+ *     configured.
+ *
+ *     Locking: tty_mutex for now
+ */
+static int tty_driver_install_tty(struct tty_driver *driver,
+                                               struct tty_struct *tty)
+{
+       int idx = tty->index;
+
+       if (driver->ops->install)
+               return driver->ops->install(driver, tty);
+
+       if (tty_init_termios(tty) == 0) {
+               tty_driver_kref_get(driver);
+               tty->count++;
+               driver->ttys[idx] = tty;
+               return 0;
+       }
+       return -ENOMEM;
+}
+
+/**
+ *     tty_driver_remove_tty() - remove a tty from the driver tables
+ *     @driver: the driver for the tty
+ *     @idx:    the minor number
+ *
+ *     Remvoe a tty object from the driver tables. The tty->index field
+ *     will be set by the time this is called.
+ *
+ *     Locking: tty_mutex for now
+ */
+static void tty_driver_remove_tty(struct tty_driver *driver,
+                                               struct tty_struct *tty)
+{
+       if (driver->ops->remove)
+               driver->ops->remove(driver, tty);
+       else
+               driver->ttys[tty->index] = NULL;
+}
+
+/*
+ *     tty_reopen()    - fast re-open of an open tty
+ *     @tty    - the tty to open
+ *
+ *     Return 0 on success, -errno on error.
+ *
+ *     Locking: tty_mutex must be held from the time the tty was found
+ *              till this open completes.
+ */
+static int tty_reopen(struct tty_struct *tty)
+{
+       struct tty_driver *driver = tty->driver;
+
+       if (test_bit(TTY_CLOSING, &tty->flags))
+               return -EIO;
+
+       if (driver->type == TTY_DRIVER_TYPE_PTY &&
+           driver->subtype == PTY_TYPE_MASTER) {
+               /*
+                * special case for PTY masters: only one open permitted,
+                * and the slave side open count is incremented as well.
+                */
+               if (tty->count)
+                       return -EIO;
+
+               tty->link->count++;
+       }
+       tty->count++;
+       tty->driver = driver; /* N.B. why do this every time?? */
+
+       WARN_ON(!test_bit(TTY_LDISC, &tty->flags));
+
+       return 0;
+}
+
+/**
+ *     tty_init_dev            -       initialise a tty device
  *     @driver: tty driver we are opening a device on
  *     @idx: device index
- *     @tty: returned tty structure
+ *     @ret_tty: returned tty structure
+ *     @first_ok: ok to open a new device (used by ptmx)
  *
  *     Prepare a tty device. This may not be a "new" clean device but
  *     could also be an active device. The pty drivers require special
@@ -1631,37 +1364,16 @@ static void tty_line_name(struct tty_driver *driver, int index, char *p)
  * relaxed for the (most common) case of reopening a tty.
  */
 
-static int init_dev(struct tty_driver *driver, int idx,
-       struct tty_struct **ret_tty)
+struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx,
+                                                               int first_ok)
 {
-       struct tty_struct *tty, *o_tty;
-       struct ktermios *tp, **tp_loc, *o_tp, **o_tp_loc;
-       struct ktermios *ltp, **ltp_loc, *o_ltp, **o_ltp_loc;
-       int retval = 0;
+       struct tty_struct *tty;
+       int retval;
 
-       /* check whether we're reopening an existing tty */
-       if (driver->flags & TTY_DRIVER_DEVPTS_MEM) {
-               tty = devpts_get_tty(idx);
-               /*
-                * If we don't have a tty here on a slave open, it's because
-                * the master already started the close process and there's
-                * no relation between devpts file and tty anymore.
-                */
-               if (!tty && driver->subtype == PTY_TYPE_SLAVE) {
-                       retval = -EIO;
-                       goto end_init;
-               }
-               /*
-                * It's safe from now on because init_dev() is called with
-                * tty_mutex held and release_dev() won't change tty->count
-                * or tty->flags without having to grab tty_mutex
-                */
-               if (tty && driver->subtype == PTY_TYPE_MASTER)
-                       tty = tty->link;
-       } else {
-               tty = driver->ttys[idx];
-       }
-       if (tty) goto fast_track;
+       /* Check if pty master is being opened multiple times */
+       if (driver->subtype == PTY_TYPE_MASTER &&
+               (driver->flags & TTY_DRIVER_DEVPTS_MEM) && !first_ok)
+               return ERR_PTR(-EIO);
 
        /*
         * First time open is complex, especially for PTY devices.
@@ -1671,189 +1383,69 @@ static int init_dev(struct tty_driver *driver, int idx,
         * and locked termios may be retained.)
         */
 
-       if (!try_module_get(driver->owner)) {
-               retval = -ENODEV;
-               goto end_init;
-       }
-
-       o_tty = NULL;
-       tp = o_tp = NULL;
-       ltp = o_ltp = NULL;
+       if (!try_module_get(driver->owner))
+               return ERR_PTR(-ENODEV);
 
        tty = alloc_tty_struct();
        if (!tty)
                goto fail_no_mem;
-       initialize_tty_struct(tty);
-       tty->driver = driver;
-       tty->ops = driver->ops;
-       tty->index = idx;
-       tty_line_name(driver, idx, tty->name);
-
-       if (driver->flags & TTY_DRIVER_DEVPTS_MEM) {
-               tp_loc = &tty->termios;
-               ltp_loc = &tty->termios_locked;
-       } else {
-               tp_loc = &driver->termios[idx];
-               ltp_loc = &driver->termios_locked[idx];
-       }
-
-       if (!*tp_loc) {
-               tp = kmalloc(sizeof(struct ktermios), GFP_KERNEL);
-               if (!tp)
-                       goto free_mem_out;
-               *tp = driver->init_termios;
-       }
-
-       if (!*ltp_loc) {
-               ltp = kzalloc(sizeof(struct ktermios), GFP_KERNEL);
-               if (!ltp)
-                       goto free_mem_out;
-       }
-
-       if (driver->type == TTY_DRIVER_TYPE_PTY) {
-               o_tty = alloc_tty_struct();
-               if (!o_tty)
-                       goto free_mem_out;
-               initialize_tty_struct(o_tty);
-               o_tty->driver = driver->other;
-               o_tty->ops = driver->ops;
-               o_tty->index = idx;
-               tty_line_name(driver->other, idx, o_tty->name);
-
-               if (driver->flags & TTY_DRIVER_DEVPTS_MEM) {
-                       o_tp_loc = &o_tty->termios;
-                       o_ltp_loc = &o_tty->termios_locked;
-               } else {
-                       o_tp_loc = &driver->other->termios[idx];
-                       o_ltp_loc = &driver->other->termios_locked[idx];
-               }
-
-               if (!*o_tp_loc) {
-                       o_tp = kmalloc(sizeof(struct ktermios), GFP_KERNEL);
-                       if (!o_tp)
-                               goto free_mem_out;
-                       *o_tp = driver->other->init_termios;
-               }
-
-               if (!*o_ltp_loc) {
-                       o_ltp = kzalloc(sizeof(struct ktermios), GFP_KERNEL);
-                       if (!o_ltp)
-                               goto free_mem_out;
-               }
+       initialize_tty_struct(tty, driver, idx);
 
-               /*
-                * Everything allocated ... set up the o_tty structure.
-                */
-               if (!(driver->other->flags & TTY_DRIVER_DEVPTS_MEM))
-                       driver->other->ttys[idx] = o_tty;
-               if (!*o_tp_loc)
-                       *o_tp_loc = o_tp;
-               if (!*o_ltp_loc)
-                       *o_ltp_loc = o_ltp;
-               o_tty->termios = *o_tp_loc;
-               o_tty->termios_locked = *o_ltp_loc;
-               driver->other->refcount++;
-               if (driver->subtype == PTY_TYPE_MASTER)
-                       o_tty->count++;
-
-               /* Establish the links in both directions */
-               tty->link   = o_tty;
-               o_tty->link = tty;
+       retval = tty_driver_install_tty(driver, tty);
+       if (retval < 0) {
+               free_tty_struct(tty);
+               module_put(driver->owner);
+               return ERR_PTR(retval);
        }
 
-       /*
-        * All structures have been allocated, so now we install them.
-        * Failures after this point use release_tty to clean up, so
-        * there's no need to null out the local pointers.
-        */
-       if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM))
-               driver->ttys[idx] = tty;
-
-       if (!*tp_loc)
-               *tp_loc = tp;
-       if (!*ltp_loc)
-               *ltp_loc = ltp;
-       tty->termios = *tp_loc;
-       tty->termios_locked = *ltp_loc;
-       /* Compatibility until drivers always set this */
-       tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios);
-       tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios);
-       driver->refcount++;
-       tty->count++;
-
        /*
         * Structures all installed ... call the ldisc open routines.
         * If we fail here just call release_tty to clean up.  No need
         * to decrement the use counts, as release_tty doesn't care.
         */
 
-       retval = tty_ldisc_setup(tty, o_tty);
-
+       retval = tty_ldisc_setup(tty, tty->link);
        if (retval)
                goto release_mem_out;
-        goto success;
-
-       /*
-        * This fast open can be used if the tty is already open.
-        * No memory is allocated, and the only failures are from
-        * attempting to open a closing tty or attempting multiple
-        * opens on a pty master.
-        */
-fast_track:
-       if (test_bit(TTY_CLOSING, &tty->flags)) {
-               retval = -EIO;
-               goto end_init;
-       }
-       if (driver->type == TTY_DRIVER_TYPE_PTY &&
-           driver->subtype == PTY_TYPE_MASTER) {
-               /*
-                * special case for PTY masters: only one open permitted,
-                * and the slave side open count is incremented as well.
-                */
-               if (tty->count) {
-                       retval = -EIO;
-                       goto end_init;
-               }
-               tty->link->count++;
-       }
-       tty->count++;
-       tty->driver = driver; /* N.B. why do this every time?? */
-
-       /* FIXME */
-       if (!test_bit(TTY_LDISC, &tty->flags))
-               printk(KERN_ERR "init_dev but no ldisc\n");
-success:
-       *ret_tty = tty;
-
-       /* All paths come through here to release the mutex */
-end_init:
-       return retval;
-
-       /* Release locally allocated memory ... nothing placed in slots */
-free_mem_out:
-       kfree(o_tp);
-       if (o_tty)
-               free_tty_struct(o_tty);
-       kfree(ltp);
-       kfree(tp);
-       free_tty_struct(tty);
+       return tty;
 
 fail_no_mem:
        module_put(driver->owner);
-       retval = -ENOMEM;
-       goto end_init;
+       return ERR_PTR(-ENOMEM);
 
        /* call the tty release_tty routine to clean out this slot */
 release_mem_out:
        if (printk_ratelimit())
-               printk(KERN_INFO "init_dev: ldisc open failed, "
+               printk(KERN_INFO "tty_init_dev: ldisc open failed, "
                                 "clearing slot %d\n", idx);
        release_tty(tty, idx);
-       goto end_init;
+       return ERR_PTR(retval);
+}
+
+void tty_free_termios(struct tty_struct *tty)
+{
+       struct ktermios *tp;
+       int idx = tty->index;
+       /* Kill this flag and push into drivers for locking etc */
+       if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) {
+               /* FIXME: Locking on ->termios array */
+               tp = tty->termios;
+               tty->driver->termios[idx] = NULL;
+               kfree(tp);
+       }
+}
+EXPORT_SYMBOL(tty_free_termios);
+
+void tty_shutdown(struct tty_struct *tty)
+{
+       tty_driver_remove_tty(tty->driver, tty);
+       tty_free_termios(tty);
 }
+EXPORT_SYMBOL(tty_shutdown);
 
 /**
  *     release_one_tty         -       release tty structure memory
+ *     @kref: kref of tty we are obliterating
  *
  *     Releases memory associated with a tty structure, and clears out the
  *     driver table slots. This function is called when a device is no longer
@@ -1863,31 +1455,19 @@ release_mem_out:
  *             tty_mutex - sometimes only
  *             takes the file list lock internally when working on the list
  *     of ttys that the driver keeps.
- *             FIXME: should we require tty_mutex is held here ??
  */
-static void release_one_tty(struct tty_struct *tty, int idx)
+static void release_one_tty(struct kref *kref)
 {
-       int devpts = tty->driver->flags & TTY_DRIVER_DEVPTS_MEM;
-       struct ktermios *tp;
-
-       if (!devpts)
-               tty->driver->ttys[idx] = NULL;
-
-       if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) {
-               tp = tty->termios;
-               if (!devpts)
-                       tty->driver->termios[idx] = NULL;
-               kfree(tp);
-
-               tp = tty->termios_locked;
-               if (!devpts)
-                       tty->driver->termios_locked[idx] = NULL;
-               kfree(tp);
-       }
-
+       struct tty_struct *tty = container_of(kref, struct tty_struct, kref);
+       struct tty_driver *driver = tty->driver;
 
+       if (tty->ops->shutdown)
+               tty->ops->shutdown(tty);
+       else
+               tty_shutdown(tty);
        tty->magic = 0;
-       tty->driver->refcount--;
+       tty_driver_kref_put(driver);
+       module_put(driver->owner);
 
        file_list_lock();
        list_del_init(&tty->tty_files);
@@ -1896,6 +1476,21 @@ static void release_one_tty(struct tty_struct *tty, int idx)
        free_tty_struct(tty);
 }
 
+/**
+ *     tty_kref_put            -       release a tty kref
+ *     @tty: tty device
+ *
+ *     Release a reference to a tty device and if need be let the kref
+ *     layer destruct the object for us
+ */
+
+void tty_kref_put(struct tty_struct *tty)
+{
+       if (tty)
+               kref_put(&tty->kref, release_one_tty);
+}
+EXPORT_SYMBOL(tty_kref_put);
+
 /**
  *     release_tty             -       release tty structure memory
  *
@@ -1907,15 +1502,16 @@ static void release_one_tty(struct tty_struct *tty, int idx)
  *             takes the file list lock internally when working on the list
  *     of ttys that the driver keeps.
  *             FIXME: should we require tty_mutex is held here ??
+ *
  */
 static void release_tty(struct tty_struct *tty, int idx)
 {
-       struct tty_driver *driver = tty->driver;
+       /* This should always be true but check for the moment */
+       WARN_ON(tty->index != idx);
 
        if (tty->link)
-               release_one_tty(tty->link, idx);
-       release_one_tty(tty, idx);
-       module_put(driver->owner);
+               tty_kref_put(tty->link);
+       tty_kref_put(tty);
 }
 
 /*
@@ -1926,20 +1522,21 @@ static void release_tty(struct tty_struct *tty, int idx)
  * WSH 09/09/97: rewritten to avoid some nasty race conditions that could
  * lead to double frees or releasing memory still in use.
  */
-static void release_dev(struct file *filp)
+void tty_release_dev(struct file *filp)
 {
        struct tty_struct *tty, *o_tty;
        int     pty_master, tty_closing, o_tty_closing, do_sleep;
        int     devpts;
        int     idx;
        char    buf[64];
+       struct  inode *inode;
 
+       inode = filp->f_path.dentry->d_inode;
        tty = (struct tty_struct *)filp->private_data;
-       if (tty_paranoia_check(tty, filp->f_path.dentry->d_inode,
-                                                       "release_dev"))
+       if (tty_paranoia_check(tty, inode, "tty_release_dev"))
                return;
 
-       check_tty_count(tty, "release_dev");
+       check_tty_count(tty, "tty_release_dev");
 
        tty_fasync(-1, filp, 0);
 
@@ -1951,33 +1548,27 @@ static void release_dev(struct file *filp)
 
 #ifdef TTY_PARANOIA_CHECK
        if (idx < 0 || idx >= tty->driver->num) {
-               printk(KERN_DEBUG "release_dev: bad idx when trying to "
+               printk(KERN_DEBUG "tty_release_dev: bad idx when trying to "
                                  "free (%s)\n", tty->name);
                return;
        }
-       if (!(tty->driver->flags & TTY_DRIVER_DEVPTS_MEM)) {
+       if (!devpts) {
                if (tty != tty->driver->ttys[idx]) {
-                       printk(KERN_DEBUG "release_dev: driver.table[%d] not tty "
+                       printk(KERN_DEBUG "tty_release_dev: driver.table[%d] not tty "
                               "for (%s)\n", idx, tty->name);
                        return;
                }
                if (tty->termios != tty->driver->termios[idx]) {
-                       printk(KERN_DEBUG "release_dev: driver.termios[%d] not termios "
+                       printk(KERN_DEBUG "tty_release_dev: driver.termios[%d] not termios "
                               "for (%s)\n",
                               idx, tty->name);
                        return;
                }
-               if (tty->termios_locked != tty->driver->termios_locked[idx]) {
-                       printk(KERN_DEBUG "release_dev: driver.termios_locked[%d] not "
-                              "termios_locked for (%s)\n",
-                              idx, tty->name);
-                       return;
-               }
        }
 #endif
 
 #ifdef TTY_DEBUG_HANGUP
-       printk(KERN_DEBUG "release_dev of %s (tty count=%d)...",
+       printk(KERN_DEBUG "tty_release_dev of %s (tty count=%d)...",
               tty_name(tty, buf), tty->count);
 #endif
 
@@ -1985,26 +1576,19 @@ static void release_dev(struct file *filp)
        if (tty->driver->other &&
             !(tty->driver->flags & TTY_DRIVER_DEVPTS_MEM)) {
                if (o_tty != tty->driver->other->ttys[idx]) {
-                       printk(KERN_DEBUG "release_dev: other->table[%d] "
+                       printk(KERN_DEBUG "tty_release_dev: other->table[%d] "
                                          "not o_tty for (%s)\n",
                               idx, tty->name);
                        return;
                }
                if (o_tty->termios != tty->driver->other->termios[idx]) {
-                       printk(KERN_DEBUG "release_dev: other->termios[%d] "
+                       printk(KERN_DEBUG "tty_release_dev: other->termios[%d] "
                                          "not o_termios for (%s)\n",
                               idx, tty->name);
                        return;
                }
-               if (o_tty->termios_locked !=
-                     tty->driver->other->termios_locked[idx]) {
-                       printk(KERN_DEBUG "release_dev: other->termios_locked["
-                                         "%d] not o_termios_locked for (%s)\n",
-                              idx, tty->name);
-                       return;
-               }
                if (o_tty->link != tty) {
-                       printk(KERN_DEBUG "release_dev: bad pty pointers\n");
+                       printk(KERN_DEBUG "tty_release_dev: bad pty pointers\n");
                        return;
                }
        }
@@ -2062,7 +1646,7 @@ static void release_dev(struct file *filp)
                if (!do_sleep)
                        break;
 
-               printk(KERN_WARNING "release_dev: %s: read/write wait queue "
+               printk(KERN_WARNING "tty_release_dev: %s: read/write wait queue "
                                    "active!\n", tty_name(tty, buf));
                mutex_unlock(&tty_mutex);
                schedule();
@@ -2075,14 +1659,14 @@ static void release_dev(struct file *filp)
         */
        if (pty_master) {
                if (--o_tty->count < 0) {
-                       printk(KERN_WARNING "release_dev: bad pty slave count "
+                       printk(KERN_WARNING "tty_release_dev: bad pty slave count "
                                            "(%d) for %s\n",
                               o_tty->count, tty_name(o_tty, buf));
                        o_tty->count = 0;
                }
        }
        if (--tty->count < 0) {
-               printk(KERN_WARNING "release_dev: bad tty->count (%d) for %s\n",
+               printk(KERN_WARNING "tty_release_dev: bad tty->count (%d) for %s\n",
                       tty->count, tty_name(tty, buf));
                tty->count = 0;
        }
@@ -2145,11 +1729,11 @@ static void release_dev(struct file *filp)
 
        /* Make this pty number available for reallocation */
        if (devpts)
-               devpts_kill_index(idx);
+               devpts_kill_index(inode, idx);
 }
 
 /**
- *     tty_open                -       open a tty device
+ *     __tty_open              -       open a tty device
  *     @inode: inode of device file
  *     @filp: file pointer to tty
  *
@@ -2164,14 +1748,14 @@ static void release_dev(struct file *filp)
  *     The termios state of a pty is reset on first open so that
  *     settings don't persist across reuse.
  *
- *     Locking: tty_mutex protects tty, get_tty_driver and init_dev work.
+ *     Locking: tty_mutex protects tty, get_tty_driver and tty_init_dev work.
  *              tty->count should protect the rest.
  *              ->siglock protects ->signal/->sighand
  */
 
 static int __tty_open(struct inode *inode, struct file *filp)
 {
-       struct tty_struct *tty;
+       struct tty_struct *tty = NULL;
        int noctty, retval;
        struct tty_driver *driver;
        int index;
@@ -2193,23 +1777,25 @@ retry_open:
                        mutex_unlock(&tty_mutex);
                        return -ENXIO;
                }
-               driver = tty->driver;
+               driver = tty_driver_kref_get(tty->driver);
                index = tty->index;
                filp->f_flags |= O_NONBLOCK; /* Don't let /dev/tty block */
                /* noctty = 1; */
+               /* FIXME: Should we take a driver reference ? */
+               tty_kref_put(tty);
                goto got_driver;
        }
 #ifdef CONFIG_VT
        if (device == MKDEV(TTY_MAJOR, 0)) {
                extern struct tty_driver *console_driver;
-               driver = console_driver;
+               driver = tty_driver_kref_get(console_driver);
                index = fg_console;
                noctty = 1;
                goto got_driver;
        }
 #endif
        if (device == MKDEV(TTYAUX_MAJOR, 1)) {
-               driver = console_device(&index);
+               driver = tty_driver_kref_get(console_device(&index));
                if (driver) {
                        /* Don't let /dev/console block */
                        filp->f_flags |= O_NONBLOCK;
@@ -2226,10 +1812,25 @@ retry_open:
                return -ENODEV;
        }
 got_driver:
-       retval = init_dev(driver, index, &tty);
+       if (!tty) {
+               /* check whether we're reopening an existing tty */
+               tty = tty_driver_lookup_tty(driver, inode, index);
+
+               if (IS_ERR(tty))
+                       return PTR_ERR(tty);
+       }
+
+       if (tty) {
+               retval = tty_reopen(tty);
+               if (retval)
+                       tty = ERR_PTR(retval);
+       } else
+               tty = tty_init_dev(driver, index, 0);
+
        mutex_unlock(&tty_mutex);
-       if (retval)
-               return retval;
+       tty_driver_kref_put(driver);
+       if (IS_ERR(tty))
+               return PTR_ERR(tty);
 
        filp->private_data = tty;
        file_move(filp, &tty->tty_files);
@@ -2257,7 +1858,7 @@ got_driver:
                printk(KERN_DEBUG "error %d in opening %s...", retval,
                       tty->name);
 #endif
-               release_dev(filp);
+               tty_release_dev(filp);
                if (retval != -ERESTARTSYS)
                        return retval;
                if (signal_pending(current))
@@ -2296,69 +1897,6 @@ static int tty_open(struct inode *inode, struct file *filp)
 
 
 
-#ifdef CONFIG_UNIX98_PTYS
-/**
- *     ptmx_open               -       open a unix 98 pty master
- *     @inode: inode of device file
- *     @filp: file pointer to tty
- *
- *     Allocate a unix98 pty master device from the ptmx driver.
- *
- *     Locking: tty_mutex protects theinit_dev work. tty->count should
- *             protect the rest.
- *             allocated_ptys_lock handles the list of free pty numbers
- */
-
-static int __ptmx_open(struct inode *inode, struct file *filp)
-{
-       struct tty_struct *tty;
-       int retval;
-       int index;
-
-       nonseekable_open(inode, filp);
-
-       /* find a device that is not in use. */
-       index = devpts_new_index();
-       if (index < 0)
-               return index;
-
-       mutex_lock(&tty_mutex);
-       retval = init_dev(ptm_driver, index, &tty);
-       mutex_unlock(&tty_mutex);
-
-       if (retval)
-               goto out;
-
-       set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
-       filp->private_data = tty;
-       file_move(filp, &tty->tty_files);
-
-       retval = devpts_pty_new(tty->link);
-       if (retval)
-               goto out1;
-
-       check_tty_count(tty, "ptmx_open");
-       retval = ptm_driver->ops->open(tty, filp);
-       if (!retval)
-               return 0;
-out1:
-       release_dev(filp);
-       return retval;
-out:
-       devpts_kill_index(index);
-       return retval;
-}
-
-static int ptmx_open(struct inode *inode, struct file *filp)
-{
-       int ret;
-
-       lock_kernel();
-       ret = __ptmx_open(inode, filp);
-       unlock_kernel();
-       return ret;
-}
-#endif
 
 /**
  *     tty_release             -       vfs callback for close
@@ -2369,13 +1907,13 @@ static int ptmx_open(struct inode *inode, struct file *filp)
  *     this tty. There may however be several such references.
  *
  *     Locking:
- *             Takes bkl. See release_dev
+ *             Takes bkl. See tty_release_dev
  */
 
 static int tty_release(struct inode *inode, struct file *filp)
 {
        lock_kernel();
-       release_dev(filp);
+       tty_release_dev(filp);
        unlock_kernel();
        return 0;
 }
@@ -2524,7 +2062,7 @@ int tty_do_resize(struct tty_struct *tty, struct tty_struct *real_tty,
 
        /* For a PTY we need to lock the tty side */
        mutex_lock(&real_tty->termios_mutex);
-       if (!memcmp(ws, &tty->winsize, sizeof(*ws)))
+       if (!memcmp(ws, &real_tty->winsize, sizeof(*ws)))
                goto done;
        /* Get the PID values and reference them so we can
           avoid holding the tty ctrl lock while sending signals */
@@ -2996,7 +2534,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        case TIOCSTI:
                return tiocsti(tty, p);
        case TIOCGWINSZ:
-               return tiocgwinsz(tty, p);
+               return tiocgwinsz(real_tty, p);
        case TIOCSWINSZ:
                return tiocswinsz(tty, real_tty, p);
        case TIOCCONS:
@@ -3026,10 +2564,6 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                return put_user(tty->ldisc.ops->num, (int __user *)p);
        case TIOCSETD:
                return tiocsetd(tty, p);
-#ifdef CONFIG_VT
-       case TIOCLINUX:
-               return tioclinux(tty, arg);
-#endif
        /*
         * Break handling
         */
@@ -3219,113 +2753,6 @@ void do_SAK(struct tty_struct *tty)
 
 EXPORT_SYMBOL(do_SAK);
 
-/**
- *     flush_to_ldisc
- *     @work: tty structure passed from work queue.
- *
- *     This routine is called out of the software interrupt to flush data
- *     from the buffer chain to the line discipline.
- *
- *     Locking: holds tty->buf.lock to guard buffer list. Drops the lock
- *     while invoking the line discipline receive_buf method. The
- *     receive_buf method is single threaded for each tty instance.
- */
-
-static void flush_to_ldisc(struct work_struct *work)
-{
-       struct tty_struct *tty =
-               container_of(work, struct tty_struct, buf.work.work);
-       unsigned long   flags;
-       struct tty_ldisc *disc;
-       struct tty_buffer *tbuf, *head;
-       char *char_buf;
-       unsigned char *flag_buf;
-
-       disc = tty_ldisc_ref(tty);
-       if (disc == NULL)       /*  !TTY_LDISC */
-               return;
-
-       spin_lock_irqsave(&tty->buf.lock, flags);
-       /* So we know a flush is running */
-       set_bit(TTY_FLUSHING, &tty->flags);
-       head = tty->buf.head;
-       if (head != NULL) {
-               tty->buf.head = NULL;
-               for (;;) {
-                       int count = head->commit - head->read;
-                       if (!count) {
-                               if (head->next == NULL)
-                                       break;
-                               tbuf = head;
-                               head = head->next;
-                               tty_buffer_free(tty, tbuf);
-                               continue;
-                       }
-                       /* Ldisc or user is trying to flush the buffers
-                          we are feeding to the ldisc, stop feeding the
-                          line discipline as we want to empty the queue */
-                       if (test_bit(TTY_FLUSHPENDING, &tty->flags))
-                               break;
-                       if (!tty->receive_room) {
-                               schedule_delayed_work(&tty->buf.work, 1);
-                               break;
-                       }
-                       if (count > tty->receive_room)
-                               count = tty->receive_room;
-                       char_buf = head->char_buf_ptr + head->read;
-                       flag_buf = head->flag_buf_ptr + head->read;
-                       head->read += count;
-                       spin_unlock_irqrestore(&tty->buf.lock, flags);
-                       disc->ops->receive_buf(tty, char_buf,
-                                                       flag_buf, count);
-                       spin_lock_irqsave(&tty->buf.lock, flags);
-               }
-               /* Restore the queue head */
-               tty->buf.head = head;
-       }
-       /* We may have a deferred request to flush the input buffer,
-          if so pull the chain under the lock and empty the queue */
-       if (test_bit(TTY_FLUSHPENDING, &tty->flags)) {
-               __tty_buffer_flush(tty);
-               clear_bit(TTY_FLUSHPENDING, &tty->flags);
-               wake_up(&tty->read_wait);
-       }
-       clear_bit(TTY_FLUSHING, &tty->flags);
-       spin_unlock_irqrestore(&tty->buf.lock, flags);
-
-       tty_ldisc_deref(disc);
-}
-
-/**
- *     tty_flip_buffer_push    -       terminal
- *     @tty: tty to push
- *
- *     Queue a push of the terminal flip buffers to the line discipline. This
- *     function must not be called from IRQ context if tty->low_latency is set.
- *
- *     In the event of the queue being busy for flipping the work will be
- *     held off and retried later.
- *
- *     Locking: tty buffer lock. Driver locks in low latency mode.
- */
-
-void tty_flip_buffer_push(struct tty_struct *tty)
-{
-       unsigned long flags;
-       spin_lock_irqsave(&tty->buf.lock, flags);
-       if (tty->buf.tail != NULL)
-               tty->buf.tail->commit = tty->buf.tail->used;
-       spin_unlock_irqrestore(&tty->buf.lock, flags);
-
-       if (tty->low_latency)
-               flush_to_ldisc(&tty->buf.work.work);
-       else
-               schedule_delayed_work(&tty->buf.work, 1);
-}
-
-EXPORT_SYMBOL(tty_flip_buffer_push);
-
-
 /**
  *     initialize_tty_struct
  *     @tty: tty to initialize
@@ -3336,9 +2763,11 @@ EXPORT_SYMBOL(tty_flip_buffer_push);
  *     Locking: none - tty in question must not be exposed at this point
  */
 
-static void initialize_tty_struct(struct tty_struct *tty)
+void initialize_tty_struct(struct tty_struct *tty,
+               struct tty_driver *driver, int idx)
 {
        memset(tty, 0, sizeof(struct tty_struct));
+       kref_init(&tty->kref);
        tty->magic = TTY_MAGIC;
        tty_ldisc_init(tty);
        tty->session = NULL;
@@ -3346,7 +2775,6 @@ static void initialize_tty_struct(struct tty_struct *tty)
        tty->overrun_time = jiffies;
        tty->buf.head = tty->buf.tail = NULL;
        tty_buffer_init(tty);
-       INIT_DELAYED_WORK(&tty->buf.work, flush_to_ldisc);
        mutex_init(&tty->termios_mutex);
        init_waitqueue_head(&tty->write_wait);
        init_waitqueue_head(&tty->read_wait);
@@ -3357,6 +2785,11 @@ static void initialize_tty_struct(struct tty_struct *tty)
        spin_lock_init(&tty->ctrl_lock);
        INIT_LIST_HEAD(&tty->tty_files);
        INIT_WORK(&tty->SAK_work, do_SAK_work);
+
+       tty->driver = driver;
+       tty->ops = driver->ops;
+       tty->index = idx;
+       tty_line_name(driver, idx, tty->name);
 }
 
 /**
@@ -3377,10 +2810,9 @@ int tty_put_char(struct tty_struct *tty, unsigned char ch)
                return tty->ops->put_char(tty, ch);
        return tty->ops->write(tty, &ch, 1);
 }
-
 EXPORT_SYMBOL_GPL(tty_put_char);
 
-static struct class *tty_class;
+struct class *tty_class;
 
 /**
  *     tty_register_device - register a tty device
@@ -3420,6 +2852,7 @@ struct device *tty_register_device(struct tty_driver *driver, unsigned index,
 
        return device_create_drvdata(tty_class, device, dev, NULL, name);
 }
+EXPORT_SYMBOL(tty_register_device);
 
 /**
  *     tty_unregister_device - unregister a tty device
@@ -3437,8 +2870,6 @@ void tty_unregister_device(struct tty_driver *driver, unsigned index)
        device_destroy(tty_class,
                MKDEV(driver->major, driver->minor_start) + index);
 }
-
-EXPORT_SYMBOL(tty_register_device);
 EXPORT_SYMBOL(tty_unregister_device);
 
 struct tty_driver *alloc_tty_driver(int lines)
@@ -3447,27 +2878,65 @@ struct tty_driver *alloc_tty_driver(int lines)
 
        driver = kzalloc(sizeof(struct tty_driver), GFP_KERNEL);
        if (driver) {
+               kref_init(&driver->kref);
                driver->magic = TTY_DRIVER_MAGIC;
                driver->num = lines;
                /* later we'll move allocation of tables here */
        }
        return driver;
 }
+EXPORT_SYMBOL(alloc_tty_driver);
 
-void put_tty_driver(struct tty_driver *driver)
+static void destruct_tty_driver(struct kref *kref)
 {
+       struct tty_driver *driver = container_of(kref, struct tty_driver, kref);
+       int i;
+       struct ktermios *tp;
+       void *p;
+
+       if (driver->flags & TTY_DRIVER_INSTALLED) {
+               /*
+                * Free the termios and termios_locked structures because
+                * we don't want to get memory leaks when modular tty
+                * drivers are removed from the kernel.
+                */
+               for (i = 0; i < driver->num; i++) {
+                       tp = driver->termios[i];
+                       if (tp) {
+                               driver->termios[i] = NULL;
+                               kfree(tp);
+                       }
+                       if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV))
+                               tty_unregister_device(driver, i);
+               }
+               p = driver->ttys;
+               proc_tty_unregister_driver(driver);
+               driver->ttys = NULL;
+               driver->termios = NULL;
+               kfree(p);
+               cdev_del(&driver->cdev);
+       }
        kfree(driver);
 }
 
+void tty_driver_kref_put(struct tty_driver *driver)
+{
+       kref_put(&driver->kref, destruct_tty_driver);
+}
+EXPORT_SYMBOL(tty_driver_kref_put);
+
 void tty_set_operations(struct tty_driver *driver,
                        const struct tty_operations *op)
 {
        driver->ops = op;
 };
+EXPORT_SYMBOL(tty_set_operations);
 
-EXPORT_SYMBOL(alloc_tty_driver);
+void put_tty_driver(struct tty_driver *d)
+{
+       tty_driver_kref_put(d);
+}
 EXPORT_SYMBOL(put_tty_driver);
-EXPORT_SYMBOL(tty_set_operations);
 
 /*
  * Called by a tty driver to register itself.
@@ -3479,11 +2948,8 @@ int tty_register_driver(struct tty_driver *driver)
        dev_t dev;
        void **p = NULL;
 
-       if (driver->flags & TTY_DRIVER_INSTALLED)
-               return 0;
-
        if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM) && driver->num) {
-               p = kzalloc(driver->num * 3 * sizeof(void *), GFP_KERNEL);
+               p = kzalloc(driver->num * 2 * sizeof(void *), GFP_KERNEL);
                if (!p)
                        return -ENOMEM;
        }
@@ -3507,12 +2973,9 @@ int tty_register_driver(struct tty_driver *driver)
        if (p) {
                driver->ttys = (struct tty_struct **)p;
                driver->termios = (struct ktermios **)(p + driver->num);
-               driver->termios_locked = (struct ktermios **)
-                                                       (p + driver->num * 2);
        } else {
                driver->ttys = NULL;
                driver->termios = NULL;
-               driver->termios_locked = NULL;
        }
 
        cdev_init(&driver->cdev, &tty_fops);
@@ -3521,7 +2984,7 @@ int tty_register_driver(struct tty_driver *driver)
        if (error) {
                unregister_chrdev_region(dev, driver->num);
                driver->ttys = NULL;
-               driver->termios = driver->termios_locked = NULL;
+               driver->termios = NULL;
                kfree(p);
                return error;
        }
@@ -3535,6 +2998,7 @@ int tty_register_driver(struct tty_driver *driver)
                    tty_register_device(driver, i, NULL);
        }
        proc_tty_register_driver(driver);
+       driver->flags |= TTY_DRIVER_INSTALLED;
        return 0;
 }
 
@@ -3545,46 +3009,19 @@ EXPORT_SYMBOL(tty_register_driver);
  */
 int tty_unregister_driver(struct tty_driver *driver)
 {
-       int i;
-       struct ktermios *tp;
-       void *p;
-
+#if 0
+       /* FIXME */
        if (driver->refcount)
                return -EBUSY;
-
+#endif
        unregister_chrdev_region(MKDEV(driver->major, driver->minor_start),
                                driver->num);
        mutex_lock(&tty_mutex);
        list_del(&driver->tty_drivers);
        mutex_unlock(&tty_mutex);
-
-       /*
-        * Free the termios and termios_locked structures because
-        * we don't want to get memory leaks when modular tty
-        * drivers are removed from the kernel.
-        */
-       for (i = 0; i < driver->num; i++) {
-               tp = driver->termios[i];
-               if (tp) {
-                       driver->termios[i] = NULL;
-                       kfree(tp);
-               }
-               tp = driver->termios_locked[i];
-               if (tp) {
-                       driver->termios_locked[i] = NULL;
-                       kfree(tp);
-               }
-               if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV))
-                       tty_unregister_device(driver, i);
-       }
-       p = driver->ttys;
-       proc_tty_unregister_driver(driver);
-       driver->ttys = NULL;
-       driver->termios = driver->termios_locked = NULL;
-       kfree(p);
-       cdev_del(&driver->cdev);
        return 0;
 }
+
 EXPORT_SYMBOL(tty_unregister_driver);
 
 dev_t tty_devnum(struct tty_struct *tty)
@@ -3595,9 +3032,12 @@ EXPORT_SYMBOL(tty_devnum);
 
 void proc_clear_tty(struct task_struct *p)
 {
+       struct tty_struct *tty;
        spin_lock_irq(&p->sighand->siglock);
+       tty = p->signal->tty;
        p->signal->tty = NULL;
        spin_unlock_irq(&p->sighand->siglock);
+       tty_kref_put(tty);
 }
 
 /* Called under the sighand lock */
@@ -3613,9 +3053,13 @@ static void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty)
                tty->pgrp = get_pid(task_pgrp(tsk));
                spin_unlock_irqrestore(&tty->ctrl_lock, flags);
                tty->session = get_pid(task_session(tsk));
+               if (tsk->signal->tty) {
+                       printk(KERN_DEBUG "tty not NULL!!\n");
+                       tty_kref_put(tsk->signal->tty);
+               }
        }
        put_pid(tsk->signal->tty_old_pgrp);
-       tsk->signal->tty = tty;
+       tsk->signal->tty = tty_kref_get(tty);
        tsk->signal->tty_old_pgrp = NULL;
 }
 
@@ -3629,18 +3073,20 @@ static void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty)
 struct tty_struct *get_current_tty(void)
 {
        struct tty_struct *tty;
-       WARN_ON_ONCE(!mutex_is_locked(&tty_mutex));
-       tty = current->signal->tty;
-       /*
-        * session->tty can be changed/cleared from under us, make sure we
-        * issue the load. The obtained pointer, when not NULL, is valid as
-        * long as we hold tty_mutex.
-        */
-       barrier();
+       unsigned long flags;
+
+       spin_lock_irqsave(&current->sighand->siglock, flags);
+       tty = tty_kref_get(current->signal->tty);
+       spin_unlock_irqrestore(&current->sighand->siglock, flags);
        return tty;
 }
 EXPORT_SYMBOL_GPL(get_current_tty);
 
+void tty_default_fops(struct file_operations *fops)
+{
+       *fops = tty_fops;
+}
+
 /*
  * Initialize the console device. This is called *early*, so
  * we can't necessarily depend on lots of kernel help here.
@@ -3678,12 +3124,6 @@ postcore_initcall(tty_class_init);
 /* 3/2004 jmc: why do these devices exist? */
 
 static struct cdev tty_cdev, console_cdev;
-#ifdef CONFIG_UNIX98_PTYS
-static struct cdev ptmx_cdev;
-#endif
-#ifdef CONFIG_VT
-static struct cdev vc0_cdev;
-#endif
 
 /*
  * Ok, now we can initialize the rest of the tty devices and can count
@@ -3695,32 +3135,18 @@ static int __init tty_init(void)
        if (cdev_add(&tty_cdev, MKDEV(TTYAUX_MAJOR, 0), 1) ||
            register_chrdev_region(MKDEV(TTYAUX_MAJOR, 0), 1, "/dev/tty") < 0)
                panic("Couldn't register /dev/tty driver\n");
-       device_create_drvdata(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), NULL,
+       device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), NULL,
                              "tty");
 
        cdev_init(&console_cdev, &console_fops);
        if (cdev_add(&console_cdev, MKDEV(TTYAUX_MAJOR, 1), 1) ||
            register_chrdev_region(MKDEV(TTYAUX_MAJOR, 1), 1, "/dev/console") < 0)
                panic("Couldn't register /dev/console driver\n");
-       device_create_drvdata(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1), NULL,
+       device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1), NULL,
                              "console");
 
-#ifdef CONFIG_UNIX98_PTYS
-       cdev_init(&ptmx_cdev, &ptmx_fops);
-       if (cdev_add(&ptmx_cdev, MKDEV(TTYAUX_MAJOR, 2), 1) ||
-           register_chrdev_region(MKDEV(TTYAUX_MAJOR, 2), 1, "/dev/ptmx") < 0)
-               panic("Couldn't register /dev/ptmx driver\n");
-       device_create_drvdata(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx");
-#endif
-
 #ifdef CONFIG_VT
-       cdev_init(&vc0_cdev, &console_fops);
-       if (cdev_add(&vc0_cdev, MKDEV(TTY_MAJOR, 0), 1) ||
-           register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0)
-               panic("Couldn't register /dev/tty0 driver\n");
-       device_create_drvdata(tty_class, NULL, MKDEV(TTY_MAJOR, 0), NULL, "tty0");
-
-       vty_init();
+       vty_init(&console_fops);
 #endif
        return 0;
 }
index bf34e45974212fc46df349416646779d2e7d78dd..a408c8e487ec006147078f2f7d22b6bce88925bb 100644 (file)
 #define TERMIOS_OLD    8
 
 
+/**
+ *     tty_chars_in_buffer     -       characters pending
+ *     @tty: terminal
+ *
+ *     Return the number of bytes of data in the device private
+ *     output queue. If no private method is supplied there is assumed
+ *     to be no queue on the device.
+ */
+
 int tty_chars_in_buffer(struct tty_struct *tty)
 {
        if (tty->ops->chars_in_buffer)
@@ -47,26 +56,49 @@ int tty_chars_in_buffer(struct tty_struct *tty)
        else
                return 0;
 }
-
 EXPORT_SYMBOL(tty_chars_in_buffer);
 
+/**
+ *     tty_write_room          -       write queue space
+ *     @tty: terminal
+ *
+ *     Return the number of bytes that can be queued to this device
+ *     at the present time. The result should be treated as a guarantee
+ *     and the driver cannot offer a value it later shrinks by more than
+ *     the number of bytes written. If no method is provided 2K is always
+ *     returned and data may be lost as there will be no flow control.
+ */
 int tty_write_room(struct tty_struct *tty)
 {
        if (tty->ops->write_room)
                return tty->ops->write_room(tty);
        return 2048;
 }
-
 EXPORT_SYMBOL(tty_write_room);
 
+/**
+ *     tty_driver_flush_buffer -       discard internal buffer
+ *     @tty: terminal
+ *
+ *     Discard the internal output buffer for this device. If no method
+ *     is provided then either the buffer cannot be hardware flushed or
+ *     there is no buffer driver side.
+ */
 void tty_driver_flush_buffer(struct tty_struct *tty)
 {
        if (tty->ops->flush_buffer)
                tty->ops->flush_buffer(tty);
 }
-
 EXPORT_SYMBOL(tty_driver_flush_buffer);
 
+/**
+ *     tty_throttle            -       flow control
+ *     @tty: terminal
+ *
+ *     Indicate that a tty should stop transmitting data down the stack.
+ */
+
 void tty_throttle(struct tty_struct *tty)
 {
        /* check TTY_THROTTLED first so it indicates our state */
@@ -76,6 +108,13 @@ void tty_throttle(struct tty_struct *tty)
 }
 EXPORT_SYMBOL(tty_throttle);
 
+/**
+ *     tty_unthrottle          -       flow control
+ *     @tty: terminal
+ *
+ *     Indicate that a tty may continue transmitting data down the stack.
+ */
+
 void tty_unthrottle(struct tty_struct *tty)
 {
        if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) &&
@@ -112,6 +151,11 @@ void tty_wait_until_sent(struct tty_struct *tty, long timeout)
 }
 EXPORT_SYMBOL(tty_wait_until_sent);
 
+
+/*
+ *             Termios Helper Methods
+ */
+
 static void unset_locked_termios(struct ktermios *termios,
                                 struct ktermios *old,
                                 struct ktermios *locked)
@@ -346,6 +390,16 @@ void tty_termios_encode_baud_rate(struct ktermios *termios,
 }
 EXPORT_SYMBOL_GPL(tty_termios_encode_baud_rate);
 
+/**
+ *     tty_encode_baud_rate            -       set baud rate of the tty
+ *     @ibaud: input baud rate
+ *     @obad: output baud rate
+ *
+ *     Update the current termios data for the tty with the new speed
+ *     settings. The caller must hold the termios_mutex for the tty in
+ *     question.
+ */
+
 void tty_encode_baud_rate(struct tty_struct *tty, speed_t ibaud, speed_t obaud)
 {
        tty_termios_encode_baud_rate(tty->termios, ibaud, obaud);
@@ -430,12 +484,11 @@ EXPORT_SYMBOL(tty_termios_hw_change);
  *     is a bit of layering violation here with n_tty in terms of the
  *     internal knowledge of this function.
  *
- *     Locking: termios_sem
+ *     Locking: termios_mutex
  */
 
 static void change_termios(struct tty_struct *tty, struct ktermios *new_termios)
 {
-       int canon_change;
        struct ktermios old_termios;
        struct tty_ldisc *ld;
        unsigned long flags;
@@ -451,18 +504,6 @@ static void change_termios(struct tty_struct *tty, struct ktermios *new_termios)
        old_termios = *tty->termios;
        *tty->termios = *new_termios;
        unset_locked_termios(tty->termios, &old_termios, tty->termios_locked);
-       canon_change = (old_termios.c_lflag ^ tty->termios->c_lflag) & ICANON;
-       if (canon_change) {
-               memset(&tty->read_flags, 0, sizeof tty->read_flags);
-               tty->canon_head = tty->read_tail;
-               tty->canon_data = 0;
-               tty->erasing = 0;
-       }
-
-       /* This bit should be in the ldisc code */
-       if (canon_change && !L_ICANON(tty) && tty->read_cnt)
-               /* Get characters left over from canonical mode. */
-               wake_up_interruptible(&tty->read_wait);
 
        /* See if packet mode change of state. */
        if (tty->link && tty->link->packet) {
@@ -508,7 +549,7 @@ static void change_termios(struct tty_struct *tty, struct ktermios *new_termios)
  *     functions before using change_termios to do the actual changes.
  *
  *     Locking:
- *             Called functions take ldisc and termios_sem locks
+ *             Called functions take ldisc and termios_mutex locks
  */
 
 static int set_termios(struct tty_struct *tty, void __user *arg, int opt)
@@ -579,25 +620,51 @@ static int get_termio(struct tty_struct *tty, struct termio __user *termio)
        return 0;
 }
 
-static unsigned long inq_canon(struct tty_struct *tty)
+
+#ifdef TCGETX
+
+/**
+ *     set_termiox     -       set termiox fields if possible
+ *     @tty: terminal
+ *     @arg: termiox structure from user
+ *     @opt: option flags for ioctl type
+ *
+ *     Implement the device calling points for the SYS5 termiox ioctl
+ *     interface in Linux
+ */
+
+static int set_termiox(struct tty_struct *tty, void __user *arg, int opt)
 {
-       int nr, head, tail;
+       struct termiox tnew;
+       struct tty_ldisc *ld;
 
-       if (!tty->canon_data || !tty->read_buf)
-               return 0;
-       head = tty->canon_head;
-       tail = tty->read_tail;
-       nr = (head - tail) & (N_TTY_BUF_SIZE-1);
-       /* Skip EOF-chars.. */
-       while (head != tail) {
-               if (test_bit(tail, tty->read_flags) &&
-                   tty->read_buf[tail] == __DISABLED_CHAR)
-                       nr--;
-               tail = (tail+1) & (N_TTY_BUF_SIZE-1);
+       if (tty->termiox == NULL)
+               return -EINVAL;
+       if (copy_from_user(&tnew, arg, sizeof(struct termiox)))
+               return -EFAULT;
+
+       ld = tty_ldisc_ref(tty);
+       if (ld != NULL) {
+               if ((opt & TERMIOS_FLUSH) && ld->ops->flush_buffer)
+                       ld->ops->flush_buffer(tty);
+               tty_ldisc_deref(ld);
        }
-       return nr;
+       if (opt & TERMIOS_WAIT) {
+               tty_wait_until_sent(tty, 0);
+               if (signal_pending(current))
+                       return -EINTR;
+       }
+
+       mutex_lock(&tty->termios_mutex);
+       if (tty->ops->set_termiox)
+               tty->ops->set_termiox(tty, &tnew);
+       mutex_unlock(&tty->termios_mutex);
+       return 0;
 }
 
+#endif
+
+
 #ifdef TIOCGETP
 /*
  * These are deprecated, but there is limited support..
@@ -671,7 +738,7 @@ static void set_sgflags(struct ktermios *termios, int flags)
  *     Updates a terminal from the legacy BSD style terminal information
  *     structure.
  *
- *     Locking: termios_sem
+ *     Locking: termios_mutex
  */
 
 static int set_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
@@ -849,6 +916,7 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
 {
        struct tty_struct *real_tty;
        void __user *p = (void __user *)arg;
+       int ret = 0;
 
        if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
            tty->driver->subtype == PTY_TYPE_MASTER)
@@ -884,18 +952,24 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
                return set_termios(real_tty, p, TERMIOS_OLD);
 #ifndef TCGETS2
        case TCGETS:
+               mutex_lock(&real_tty->termios_mutex);
                if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios))
-                       return -EFAULT;
-               return 0;
+                       ret = -EFAULT;
+               mutex_unlock(&real_tty->termios_mutex);
+               return ret;
 #else
        case TCGETS:
+               mutex_lock(&real_tty->termios_mutex);
                if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios))
-                       return -EFAULT;
-               return 0;
+                       ret = -EFAULT;
+               mutex_unlock(&real_tty->termios_mutex);
+               return ret;
        case TCGETS2:
+               mutex_lock(&real_tty->termios_mutex);
                if (kernel_termios_to_user_termios((struct termios2 __user *)arg, real_tty->termios))
-                       return -EFAULT;
-               return 0;
+                       ret = -EFAULT;
+               mutex_unlock(&real_tty->termios_mutex);
+               return ret;
        case TCSETSF2:
                return set_termios(real_tty, p,  TERMIOS_FLUSH | TERMIOS_WAIT);
        case TCSETSW2:
@@ -913,34 +987,59 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
                return set_termios(real_tty, p, TERMIOS_TERMIO);
 #ifndef TCGETS2
        case TIOCGLCKTRMIOS:
+               mutex_lock(&real_tty->termios_mutex);
                if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios_locked))
-                       return -EFAULT;
-               return 0;
+                       ret = -EFAULT;
+               mutex_unlock(&real_tty->termios_mutex);
+               return ret;
        case TIOCSLCKTRMIOS:
                if (!capable(CAP_SYS_ADMIN))
                        return -EPERM;
+               mutex_lock(&real_tty->termios_mutex);
                if (user_termios_to_kernel_termios(real_tty->termios_locked,
                                               (struct termios __user *) arg))
-                       return -EFAULT;
-               return 0;
+                       ret = -EFAULT;
+               mutex_unlock(&real_tty->termios_mutex);
+               return ret;
 #else
        case TIOCGLCKTRMIOS:
+               mutex_lock(&real_tty->termios_mutex);
                if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios_locked))
-                       return -EFAULT;
-               return 0;
+                       ret = -EFAULT;
+               mutex_unlock(&real_tty->termios_mutex);
+               return ret;
        case TIOCSLCKTRMIOS:
                if (!capable(CAP_SYS_ADMIN))
-                       return -EPERM;
+                       ret = -EPERM;
+               mutex_lock(&real_tty->termios_mutex);
                if (user_termios_to_kernel_termios_1(real_tty->termios_locked,
                                               (struct termios __user *) arg))
-                       return -EFAULT;
-                       return 0;
+                       ret = -EFAULT;
+               mutex_unlock(&real_tty->termios_mutex);
+               return ret;
 #endif
+#ifdef TCGETX
+       case TCGETX:
+               if (real_tty->termiox == NULL)
+                       return -EINVAL;
+               mutex_lock(&real_tty->termios_mutex);
+               if (copy_to_user(p, real_tty->termiox, sizeof(struct termiox)))
+                       ret = -EFAULT;
+               mutex_unlock(&real_tty->termios_mutex);
+               return ret;
+       case TCSETX:
+               return set_termiox(real_tty, p, 0);
+       case TCSETXW:
+               return set_termiox(real_tty, p, TERMIOS_WAIT);
+       case TCSETXF:
+               return set_termiox(real_tty, p, TERMIOS_FLUSH);
+#endif         
        case TIOCGSOFTCAR:
-               /* FIXME: for correctness we may need to take the termios
-                  lock here - review */
-               return put_user(C_CLOCAL(real_tty) ? 1 : 0,
+               mutex_lock(&real_tty->termios_mutex);
+               ret = put_user(C_CLOCAL(real_tty) ? 1 : 0,
                                                (int __user *)arg);
+               mutex_unlock(&real_tty->termios_mutex);
+               return ret;
        case TIOCSSOFTCAR:
                if (get_user(arg, (unsigned int __user *) arg))
                        return -EFAULT;
@@ -980,7 +1079,7 @@ int tty_perform_flush(struct tty_struct *tty, unsigned long arg)
 }
 EXPORT_SYMBOL_GPL(tty_perform_flush);
 
-int n_tty_ioctl(struct tty_struct *tty, struct file *file,
+int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file,
                       unsigned int cmd, unsigned long arg)
 {
        unsigned long flags;
@@ -1018,13 +1117,6 @@ int n_tty_ioctl(struct tty_struct *tty, struct file *file,
                return 0;
        case TCFLSH:
                return tty_perform_flush(tty, arg);
-       case TIOCOUTQ:
-               return put_user(tty_chars_in_buffer(tty), (int __user *) arg);
-       case TIOCINQ:
-               retval = tty->read_cnt;
-               if (L_ICANON(tty))
-                       retval = inq_canon(tty);
-               return put_user(retval, (unsigned int __user *) arg);
        case TIOCPKT:
        {
                int pktmode;
@@ -1050,4 +1142,4 @@ int n_tty_ioctl(struct tty_struct *tty, struct file *file,
                return tty_mode_ioctl(tty, file, cmd, arg);
        }
 }
-EXPORT_SYMBOL(n_tty_ioctl);
+EXPORT_SYMBOL(n_tty_ioctl_helper);
diff --git a/drivers/char/tty_port.c b/drivers/char/tty_port.c
new file mode 100644 (file)
index 0000000..553b0e9
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Tty port functions
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/timer.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/wait.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+
+void tty_port_init(struct tty_port *port)
+{
+       memset(port, 0, sizeof(*port));
+       init_waitqueue_head(&port->open_wait);
+       init_waitqueue_head(&port->close_wait);
+       mutex_init(&port->mutex);
+       spin_lock_init(&port->lock);
+       port->close_delay = (50 * HZ) / 100;
+       port->closing_wait = (3000 * HZ) / 100;
+}
+EXPORT_SYMBOL(tty_port_init);
+
+int tty_port_alloc_xmit_buf(struct tty_port *port)
+{
+       /* We may sleep in get_zeroed_page() */
+       mutex_lock(&port->mutex);
+       if (port->xmit_buf == NULL)
+               port->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL);
+       mutex_unlock(&port->mutex);
+       if (port->xmit_buf == NULL)
+               return -ENOMEM;
+       return 0;
+}
+EXPORT_SYMBOL(tty_port_alloc_xmit_buf);
+
+void tty_port_free_xmit_buf(struct tty_port *port)
+{
+       mutex_lock(&port->mutex);
+       if (port->xmit_buf != NULL) {
+               free_page((unsigned long)port->xmit_buf);
+               port->xmit_buf = NULL;
+       }
+       mutex_unlock(&port->mutex);
+}
+EXPORT_SYMBOL(tty_port_free_xmit_buf);
+
+
+/**
+ *     tty_port_tty_get        -       get a tty reference
+ *     @port: tty port
+ *
+ *     Return a refcount protected tty instance or NULL if the port is not
+ *     associated with a tty (eg due to close or hangup)
+ */
+
+struct tty_struct *tty_port_tty_get(struct tty_port *port)
+{
+       unsigned long flags;
+       struct tty_struct *tty;
+
+       spin_lock_irqsave(&port->lock, flags);
+       tty = tty_kref_get(port->tty);
+       spin_unlock_irqrestore(&port->lock, flags);
+       return tty;
+}
+EXPORT_SYMBOL(tty_port_tty_get);
+
+/**
+ *     tty_port_tty_set        -       set the tty of a port
+ *     @port: tty port
+ *     @tty: the tty
+ *
+ *     Associate the port and tty pair. Manages any internal refcounts.
+ *     Pass NULL to deassociate a port
+ */
+
+void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+       if (port->tty)
+               tty_kref_put(port->tty);
+       port->tty = tty;
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+EXPORT_SYMBOL(tty_port_tty_set);
index 60359c360912c7d4dddee8e76a6a4ffb2c576e7e..57029fefd64a65fec4bfbb0e69a1915e8aa4359a 100644 (file)
 #include <linux/font.h>
 #include <linux/bitops.h>
 #include <linux/notifier.h>
-
-#include <asm/io.h>
+#include <linux/device.h>
+#include <linux/io.h>
 #include <asm/system.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 
 #define MAX_NR_CON_DRIVER 16
 
@@ -2136,27 +2136,9 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co
            release_console_sem();
            return 0;
        }
-       release_console_sem();
-
        orig_buf = buf;
        orig_count = count;
 
-       /* At this point 'buf' is guaranteed to be a kernel buffer
-        * and therefore no access to userspace (and therefore sleeping)
-        * will be needed.  The con_buf_mtx serializes all tty based
-        * console rendering and vcs write/read operations.  We hold
-        * the console spinlock during the entire write.
-        */
-
-       acquire_console_sem();
-
-       vc = tty->driver_data;
-       if (vc == NULL) {
-               printk(KERN_ERR "vt: argh, driver_data _became_ NULL !\n");
-               release_console_sem();
-               goto out;
-       }
-
        himask = vc->vc_hi_font_mask;
        charmask = himask ? 0x1ff : 0xff;
 
@@ -2370,8 +2352,6 @@ rescan_last_byte:
        FLUSH
        console_conditional_schedule();
        release_console_sem();
-
-out:
        notify_update(vc);
        return n;
 #undef FLUSH
@@ -2583,8 +2563,6 @@ int tioclinux(struct tty_struct *tty, unsigned long arg)
        int lines;
        int ret;
 
-       if (tty->driver->type != TTY_DRIVER_TYPE_CONSOLE)
-               return -EINVAL;
        if (current->signal->tty != tty && !capable(CAP_SYS_ADMIN))
                return -EPERM;
        if (get_user(type, p))
@@ -2778,6 +2756,12 @@ static int con_open(struct tty_struct *tty, struct file *filp)
                ret = vc_allocate(currcons);
                if (ret == 0) {
                        struct vc_data *vc = vc_cons[currcons].d;
+
+                       /* Still being freed */
+                       if (vc->vc_tty) {
+                               release_console_sem();
+                               return -ERESTARTSYS;
+                       }
                        tty->driver_data = vc;
                        vc->vc_tty = tty;
 
@@ -2798,34 +2782,20 @@ static int con_open(struct tty_struct *tty, struct file *filp)
        return ret;
 }
 
-/*
- * We take tty_mutex in here to prevent another thread from coming in via init_dev
- * and taking a ref against the tty while we're in the process of forgetting
- * about it and cleaning things up.
- *
- * This is because vcs_remove_sysfs() can sleep and will drop the BKL.
- */
 static void con_close(struct tty_struct *tty, struct file *filp)
 {
-       mutex_lock(&tty_mutex);
-       acquire_console_sem();
-       if (tty && tty->count == 1) {
-               struct vc_data *vc = tty->driver_data;
+       /* Nothing to do - we defer to shutdown */
+}
 
-               if (vc)
-                       vc->vc_tty = NULL;
-               tty->driver_data = NULL;
-               vcs_remove_sysfs(tty);
-               release_console_sem();
-               mutex_unlock(&tty_mutex);
-               /*
-                * tty_mutex is released, but we still hold BKL, so there is
-                * still exclusion against init_dev()
-                */
-               return;
-       }
+static void con_shutdown(struct tty_struct *tty)
+{
+       struct vc_data *vc = tty->driver_data;
+       BUG_ON(vc == NULL);
+       acquire_console_sem();
+       vc->vc_tty = NULL;
+       vcs_remove_sysfs(tty);
        release_console_sem();
-       mutex_unlock(&tty_mutex);
+       tty_shutdown(tty);
 }
 
 static int default_italic_color    = 2; // green (ASCII)
@@ -2950,10 +2920,19 @@ static const struct tty_operations con_ops = {
        .throttle = con_throttle,
        .unthrottle = con_unthrottle,
        .resize = vt_resize,
+       .shutdown = con_shutdown
 };
 
-int __init vty_init(void)
+static struct cdev vc0_cdev;
+
+int __init vty_init(const struct file_operations *console_fops)
 {
+       cdev_init(&vc0_cdev, console_fops);
+       if (cdev_add(&vc0_cdev, MKDEV(TTY_MAJOR, 0), 1) ||
+           register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0)
+               panic("Couldn't register /dev/tty0 driver\n");
+       device_create(tty_class, NULL, MKDEV(TTY_MAJOR, 0), NULL, "tty0");
+
        vcs_init();
 
        console_driver = alloc_tty_driver(MAX_NR_CONSOLES);
@@ -2972,7 +2951,6 @@ int __init vty_init(void)
        tty_set_operations(console_driver, &con_ops);
        if (tty_register_driver(console_driver))
                panic("Couldn't register console driver\n");
-
        kbd_init();
        console_map_init();
 #ifdef CONFIG_PROM_CONSOLE
@@ -3466,7 +3444,7 @@ int register_con_driver(const struct consw *csw, int first, int last)
        if (retval)
                goto err;
 
-       con_driver->dev = device_create_drvdata(vtconsole_class, NULL,
+       con_driver->dev = device_create(vtconsole_class, NULL,
                                                MKDEV(0, con_driver->node),
                                                NULL, "vtcon%i",
                                                con_driver->node);
@@ -3577,7 +3555,7 @@ static int __init vtconsole_class_init(void)
                struct con_driver *con = &registered_con_driver[i];
 
                if (con->con && !con->dev) {
-                       con->dev = device_create_drvdata(vtconsole_class, NULL,
+                       con->dev = device_create(vtconsole_class, NULL,
                                                         MKDEV(0, con->node),
                                                         NULL, "vtcon%i",
                                                         con->node);
index c904e9ad4a71a396d5fa3c06747065b99335d392..8944ce508e2fea56a489501023a7dcdc8a22bb81 100644 (file)
@@ -395,6 +395,8 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
  
        kbd = kbd_table + console;
        switch (cmd) {
+       case TIOCLINUX:
+               return tioclinux(tty, arg);
        case KIOCSOUND:
                if (!perm)
                        goto eperm;
index 871b0cbca5e4540299047294d02c40a20326345a..798d7f3e42efbcaad5e871b0590a6cc77933fbc1 100644 (file)
@@ -1231,7 +1231,7 @@ static int capinc_tty_ioctl(struct tty_struct *tty, struct file * file,
        int error = 0;
        switch (cmd) {
        default:
-               error = n_tty_ioctl (tty, file, cmd, arg);
+               error = n_tty_ioctl_helper(tty, file, cmd, arg);
                break;
        }
        return error;
index 5e89fa177816f54b45bce84cf65ba3dd09f01b34..07052ed2a0c56d46480cb04c375df1afc3779d31 100644 (file)
@@ -571,6 +571,7 @@ gigaset_tty_close(struct tty_struct *tty)
        }
 
        /* prevent other callers from entering ldisc methods */
+       /* FIXME: should use the tty state flags */
        tty->disc_data = NULL;
 
        if (!cs->hw.ser)
@@ -642,10 +643,11 @@ gigaset_tty_ioctl(struct tty_struct *tty, struct file *file,
                return -ENXIO;
 
        switch (cmd) {
-       case TCGETS:
-       case TCGETA:
-               /* pass through to underlying serial device */
-               rc = n_tty_ioctl(tty, file, cmd, arg);
+
+       case FIONREAD:
+               /* unused, always return zero */
+               val = 0;
+               rc = put_user(val, p);
                break;
 
        case TCFLSH:
@@ -659,20 +661,13 @@ gigaset_tty_ioctl(struct tty_struct *tty, struct file *file,
                        flush_send_queue(cs);
                        break;
                }
-               /* flush the serial port's buffer */
-               rc = n_tty_ioctl(tty, file, cmd, arg);
-               break;
-
-       case FIONREAD:
-               /* unused, always return zero */
-               val = 0;
-               rc = put_user(val, p);
-               break;
+               /* Pass through */
 
        default:
-               rc = -ENOIOCTLCMD;
+               /* pass through to underlying serial device */
+               rc = n_tty_ioctl_helper(tty, file, cmd, arg);
+               break;
        }
-
        cs_put(cs);
        return rc;
 }
@@ -680,6 +675,8 @@ gigaset_tty_ioctl(struct tty_struct *tty, struct file *file,
 /*
  * Poll on the tty.
  * Unused, always return zero.
+ *
+ * FIXME: should probably return an exception - especially on hangup
  */
 static unsigned int
 gigaset_tty_poll(struct tty_struct *tty, struct file *file, poll_table *wait)
index 5405c30dbb041748b47941c5e9b0fd19842915c4..08efbe7254ff428d51e5bb734715754f1acdb2f6 100644 (file)
@@ -2092,15 +2092,8 @@ static int cafe_pci_probe(struct pci_dev *pdev,
                const struct pci_device_id *id)
 {
        int ret;
-       u16 classword;
        struct cafe_camera *cam;
-       /*
-        * Make sure we have a camera here - we'll get calls for
-        * the other cafe devices as well.
-        */
-       pci_read_config_word(pdev, PCI_CLASS_DEVICE, &classword);
-       if (classword != PCI_CLASS_MULTIMEDIA_VIDEO)
-               return -ENODEV;
+
        /*
         * Start putting together one of our big camera structures.
         */
@@ -2288,8 +2281,8 @@ static int cafe_pci_resume(struct pci_dev *pdev)
 
 
 static struct pci_device_id cafe_ids[] = {
-       { PCI_DEVICE(0x11ab, 0x4100) }, /* Eventual real ID */
-       { PCI_DEVICE(0x11ab, 0x4102) }, /* Really eventual real ID */
+       { PCI_DEVICE(PCI_VENDOR_ID_MARVELL,
+                    PCI_DEVICE_ID_MARVELL_88ALP01_CCIC) },
        { 0, }
 };
 
index 0a84f10d719c2e2a8f4c37b4696bc3f1dc1e7d2b..9bd7026b0021bbc0aa15fadedd79ae0471844767 100644 (file)
@@ -327,7 +327,7 @@ static const struct pci_device_id pci_ids[] __devinitdata = {
 
        {
                .vendor         = PCI_VENDOR_ID_MARVELL,
-               .device         = PCI_DEVICE_ID_MARVELL_CAFE_SD,
+               .device         = PCI_DEVICE_ID_MARVELL_88ALP01_SD,
                .subvendor      = PCI_ANY_ID,
                .subdevice      = PCI_ANY_ID,
                .driver_data    = (kernel_ulong_t)&sdhci_cafe,
index 95345d05157922fdfedf21b6a7d9527215f40be3..b8064bf3aee43d45f086ddbf3675fae71a696c25 100644 (file)
@@ -1,6 +1,9 @@
 /*
  * Driver for One Laptop Per Child ‘CAFÉ’ controller, aka Marvell 88ALP01
  *
+ * The data sheet for this device can be found at:
+ *    http://www.marvell.com/products/pcconn/88ALP01.jsp
+ *
  * Copyright © 2006 Red Hat, Inc.
  * Copyright © 2006 David Woodhouse <dwmw2@infradead.org>
  */
@@ -842,7 +845,8 @@ static void __devexit cafe_nand_remove(struct pci_dev *pdev)
 }
 
 static struct pci_device_id cafe_nand_tbl[] = {
-       { 0x11ab, 0x4100, PCI_ANY_ID, PCI_ANY_ID },
+       { PCI_VENDOR_ID_MARVELL, PCI_DEVICE_ID_MARVELL_88ALP01_NAND,
+         PCI_ANY_ID, PCI_ANY_ID },
        { }
 };
 
index 2ae2ec40015d9cb33faa34defcbe220698196729..21efd99b9294bac7a17ce21763f4074e65596ef1 100644 (file)
@@ -205,7 +205,7 @@ config WANXL_BUILD_FIRMWARE
 
 config PC300
        tristate "Cyclades-PC300 support (RS-232/V.35, X.21, T1/E1 boards)"
-       depends on HDLC && PCI
+       depends on HDLC && PCI && BROKEN
        ---help---
          Driver for the Cyclades-PC300 synchronous communication boards.
 
index 9304c45550790c7e2f1f53833d4370ac051b3f4f..ed982273fb8b1d9311aba68a3b2a42de5d174e78 100644 (file)
@@ -5,6 +5,7 @@
  * @remark Read the file COPYING
  *
  * @author John Levon <levon@movementarian.org>
+ * @author Barry Kasindorf
  *
  * This is the core of the buffer management. Each
  * CPU buffer is processed and entered into the
@@ -33,7 +34,7 @@
 #include "event_buffer.h"
 #include "cpu_buffer.h"
 #include "buffer_sync.h"
+
 static LIST_HEAD(dying_tasks);
 static LIST_HEAD(dead_tasks);
 static cpumask_t marked_cpus = CPU_MASK_NONE;
@@ -48,10 +49,11 @@ static void process_task_mortuary(void);
  * Can be invoked from softirq via RCU callback due to
  * call_rcu() of the task struct, hence the _irqsave.
  */
-static int task_free_notify(struct notifier_block * self, unsigned long val, void * data)
+static int
+task_free_notify(struct notifier_block *self, unsigned long val, void *data)
 {
        unsigned long flags;
-       struct task_struct * task = data;
+       struct task_struct *task = data;
        spin_lock_irqsave(&task_mortuary, flags);
        list_add(&task->tasks, &dying_tasks);
        spin_unlock_irqrestore(&task_mortuary, flags);
@@ -62,13 +64,14 @@ static int task_free_notify(struct notifier_block * self, unsigned long val, voi
 /* The task is on its way out. A sync of the buffer means we can catch
  * any remaining samples for this task.
  */
-static int task_exit_notify(struct notifier_block * self, unsigned long val, void * data)
+static int
+task_exit_notify(struct notifier_block *self, unsigned long val, void *data)
 {
        /* To avoid latency problems, we only process the current CPU,
         * hoping that most samples for the task are on this CPU
         */
        sync_buffer(raw_smp_processor_id());
-       return 0;
+       return 0;
 }
 
 
@@ -77,11 +80,12 @@ static int task_exit_notify(struct notifier_block * self, unsigned long val, voi
  * we don't lose any. This does not have to be exact, it's a QoI issue
  * only.
  */
-static int munmap_notify(struct notifier_block * self, unsigned long val, void * data)
+static int
+munmap_notify(struct notifier_block *self, unsigned long val, void *data)
 {
        unsigned long addr = (unsigned long)data;
-       struct mm_struct * mm = current->mm;
-       struct vm_area_struct * mpnt;
+       struct mm_struct *mm = current->mm;
+       struct vm_area_struct *mpnt;
 
        down_read(&mm->mmap_sem);
 
@@ -99,11 +103,12 @@ static int munmap_notify(struct notifier_block * self, unsigned long val, void *
        return 0;
 }
 
+
 /* We need to be told about new modules so we don't attribute to a previously
  * loaded module, or drop the samples on the floor.
  */
-static int module_load_notify(struct notifier_block * self, unsigned long val, void * data)
+static int
+module_load_notify(struct notifier_block *self, unsigned long val, void *data)
 {
 #ifdef CONFIG_MODULES
        if (val != MODULE_STATE_COMING)
@@ -118,7 +123,7 @@ static int module_load_notify(struct notifier_block * self, unsigned long val, v
        return 0;
 }
 
+
 static struct notifier_block task_free_nb = {
        .notifier_call  = task_free_notify,
 };
@@ -135,7 +140,7 @@ static struct notifier_block module_load_nb = {
        .notifier_call = module_load_notify,
 };
 
+
 static void end_sync(void)
 {
        end_cpu_work();
@@ -208,14 +213,14 @@ static inline unsigned long fast_get_dcookie(struct path *path)
  * not strictly necessary but allows oprofile to associate
  * shared-library samples with particular applications
  */
-static unsigned long get_exec_dcookie(struct mm_struct * mm)
+static unsigned long get_exec_dcookie(struct mm_struct *mm)
 {
        unsigned long cookie = NO_COOKIE;
-       struct vm_area_struct * vma;
+       struct vm_area_struct *vma;
+
        if (!mm)
                goto out;
+
        for (vma = mm->mmap; vma; vma = vma->vm_next) {
                if (!vma->vm_file)
                        continue;
@@ -235,13 +240,14 @@ out:
  * sure to do this lookup before a mm->mmap modification happens so
  * we don't lose track.
  */
-static unsigned long lookup_dcookie(struct mm_struct * mm, unsigned long addr, off_t * offset)
+static unsigned long
+lookup_dcookie(struct mm_struct *mm, unsigned long addr, off_t *offset)
 {
        unsigned long cookie = NO_COOKIE;
-       struct vm_area_struct * vma;
+       struct vm_area_struct *vma;
 
        for (vma = find_vma(mm, addr); vma; vma = vma->vm_next) {
+
                if (addr < vma->vm_start || addr >= vma->vm_end)
                        continue;
 
@@ -263,9 +269,20 @@ static unsigned long lookup_dcookie(struct mm_struct * mm, unsigned long addr, o
        return cookie;
 }
 
+static void increment_tail(struct oprofile_cpu_buffer *b)
+{
+       unsigned long new_tail = b->tail_pos + 1;
+
+       rmb();  /* be sure fifo pointers are synchromized */
+
+       if (new_tail < b->buffer_size)
+               b->tail_pos = new_tail;
+       else
+               b->tail_pos = 0;
+}
 
 static unsigned long last_cookie = INVALID_COOKIE;
+
 static void add_cpu_switch(int i)
 {
        add_event_entry(ESCAPE_CODE);
@@ -278,16 +295,16 @@ static void add_kernel_ctx_switch(unsigned int in_kernel)
 {
        add_event_entry(ESCAPE_CODE);
        if (in_kernel)
-               add_event_entry(KERNEL_ENTER_SWITCH_CODE); 
+               add_event_entry(KERNEL_ENTER_SWITCH_CODE);
        else
-               add_event_entry(KERNEL_EXIT_SWITCH_CODE); 
+               add_event_entry(KERNEL_EXIT_SWITCH_CODE);
 }
+
 static void
-add_user_ctx_switch(struct task_struct const * task, unsigned long cookie)
+add_user_ctx_switch(struct task_struct const *task, unsigned long cookie)
 {
        add_event_entry(ESCAPE_CODE);
-       add_event_entry(CTX_SWITCH_CODE); 
+       add_event_entry(CTX_SWITCH_CODE);
        add_event_entry(task->pid);
        add_event_entry(cookie);
        /* Another code for daemon back-compat */
@@ -296,7 +313,7 @@ add_user_ctx_switch(struct task_struct const * task, unsigned long cookie)
        add_event_entry(task->tgid);
 }
 
+
 static void add_cookie_switch(unsigned long cookie)
 {
        add_event_entry(ESCAPE_CODE);
@@ -304,13 +321,78 @@ static void add_cookie_switch(unsigned long cookie)
        add_event_entry(cookie);
 }
 
+
 static void add_trace_begin(void)
 {
        add_event_entry(ESCAPE_CODE);
        add_event_entry(TRACE_BEGIN_CODE);
 }
 
+#ifdef CONFIG_OPROFILE_IBS
+
+#define IBS_FETCH_CODE_SIZE    2
+#define IBS_OP_CODE_SIZE       5
+#define IBS_EIP(offset)                                \
+       (((struct op_sample *)&cpu_buf->buffer[(offset)])->eip)
+#define IBS_EVENT(offset)                              \
+       (((struct op_sample *)&cpu_buf->buffer[(offset)])->event)
+
+/*
+ * Add IBS fetch and op entries to event buffer
+ */
+static void add_ibs_begin(struct oprofile_cpu_buffer *cpu_buf, int code,
+       int in_kernel, struct mm_struct *mm)
+{
+       unsigned long rip;
+       int i, count;
+       unsigned long ibs_cookie = 0;
+       off_t offset;
+
+       increment_tail(cpu_buf);        /* move to RIP entry */
+
+       rip = IBS_EIP(cpu_buf->tail_pos);
+
+#ifdef __LP64__
+       rip += IBS_EVENT(cpu_buf->tail_pos) << 32;
+#endif
+
+       if (mm) {
+               ibs_cookie = lookup_dcookie(mm, rip, &offset);
+
+               if (ibs_cookie == NO_COOKIE)
+                       offset = rip;
+               if (ibs_cookie == INVALID_COOKIE) {
+                       atomic_inc(&oprofile_stats.sample_lost_no_mapping);
+                       offset = rip;
+               }
+               if (ibs_cookie != last_cookie) {
+                       add_cookie_switch(ibs_cookie);
+                       last_cookie = ibs_cookie;
+               }
+       } else
+               offset = rip;
+
+       add_event_entry(ESCAPE_CODE);
+       add_event_entry(code);
+       add_event_entry(offset);        /* Offset from Dcookie */
+
+       /* we send the Dcookie offset, but send the raw Linear Add also*/
+       add_event_entry(IBS_EIP(cpu_buf->tail_pos));
+       add_event_entry(IBS_EVENT(cpu_buf->tail_pos));
+
+       if (code == IBS_FETCH_CODE)
+               count = IBS_FETCH_CODE_SIZE;    /*IBS FETCH is 2 int64s*/
+       else
+               count = IBS_OP_CODE_SIZE;       /*IBS OP is 5 int64s*/
+
+       for (i = 0; i < count; i++) {
+               increment_tail(cpu_buf);
+               add_event_entry(IBS_EIP(cpu_buf->tail_pos));
+               add_event_entry(IBS_EVENT(cpu_buf->tail_pos));
+       }
+}
+
+#endif
 
 static void add_sample_entry(unsigned long offset, unsigned long event)
 {
@@ -319,13 +401,13 @@ static void add_sample_entry(unsigned long offset, unsigned long event)
 }
 
 
-static int add_us_sample(struct mm_struct * mm, struct op_sample * s)
+static int add_us_sample(struct mm_struct *mm, struct op_sample *s)
 {
        unsigned long cookie;
        off_t offset;
-       cookie = lookup_dcookie(mm, s->eip, &offset);
+
+       cookie = lookup_dcookie(mm, s->eip, &offset);
+
        if (cookie == INVALID_COOKIE) {
                atomic_inc(&oprofile_stats.sample_lost_no_mapping);
                return 0;
@@ -341,13 +423,13 @@ static int add_us_sample(struct mm_struct * mm, struct op_sample * s)
        return 1;
 }
 
+
 /* Add a sample to the global event buffer. If possible the
  * sample is converted into a persistent dentry/offset pair
  * for later lookup from userspace.
  */
 static int
-add_sample(struct mm_struct * mm, struct op_sample * s, int in_kernel)
+add_sample(struct mm_struct *mm, struct op_sample *s, int in_kernel)
 {
        if (in_kernel) {
                add_sample_entry(s->eip, s->event);
@@ -359,9 +441,9 @@ add_sample(struct mm_struct * mm, struct op_sample * s, int in_kernel)
        }
        return 0;
 }
 
-static void release_mm(struct mm_struct * mm)
+
+static void release_mm(struct mm_struct *mm)
 {
        if (!mm)
                return;
@@ -370,9 +452,9 @@ static void release_mm(struct mm_struct * mm)
 }
 
 
-static struct mm_struct * take_tasks_mm(struct task_struct * task)
+static struct mm_struct *take_tasks_mm(struct task_struct *task)
 {
-       struct mm_struct * mm = get_task_mm(task);
+       struct mm_struct *mm = get_task_mm(task);
        if (mm)
                down_read(&mm->mmap_sem);
        return mm;
@@ -383,10 +465,10 @@ static inline int is_code(unsigned long val)
 {
        return val == ESCAPE_CODE;
 }
+
 
 /* "acquire" as many cpu buffer slots as we can */
-static unsigned long get_slots(struct oprofile_cpu_buffer * b)
+static unsigned long get_slots(struct oprofile_cpu_buffer *b)
 {
        unsigned long head = b->head_pos;
        unsigned long tail = b->tail_pos;
@@ -412,19 +494,6 @@ static unsigned long get_slots(struct oprofile_cpu_buffer * b)
 }
 
 
-static void increment_tail(struct oprofile_cpu_buffer * b)
-{
-       unsigned long new_tail = b->tail_pos + 1;
-
-       rmb();
-
-       if (new_tail < b->buffer_size)
-               b->tail_pos = new_tail;
-       else
-               b->tail_pos = 0;
-}
-
-
 /* Move tasks along towards death. Any tasks on dead_tasks
  * will definitely have no remaining references in any
  * CPU buffers at this point, because we use two lists,
@@ -435,8 +504,8 @@ static void process_task_mortuary(void)
 {
        unsigned long flags;
        LIST_HEAD(local_dead_tasks);
-       struct task_struct * task;
-       struct task_struct * ttask;
+       struct task_struct *task;
+       struct task_struct *ttask;
 
        spin_lock_irqsave(&task_mortuary, flags);
 
@@ -493,7 +562,7 @@ void sync_buffer(int cpu)
 {
        struct oprofile_cpu_buffer *cpu_buf = &per_cpu(cpu_buffer, cpu);
        struct mm_struct *mm = NULL;
-       struct task_struct * new;
+       struct task_struct *new;
        unsigned long cookie = 0;
        int in_kernel = 1;
        unsigned int i;
@@ -501,7 +570,7 @@ void sync_buffer(int cpu)
        unsigned long available;
 
        mutex_lock(&buffer_mutex);
+
        add_cpu_switch(cpu);
 
        /* Remember, only we can modify tail_pos */
@@ -509,8 +578,8 @@ void sync_buffer(int cpu)
        available = get_slots(cpu_buf);
 
        for (i = 0; i < available; ++i) {
-               struct op_sample * s = &cpu_buf->buffer[cpu_buf->tail_pos];
+               struct op_sample *s = &cpu_buf->buffer[cpu_buf->tail_pos];
+
                if (is_code(s->eip)) {
                        if (s->event <= CPU_IS_KERNEL) {
                                /* kernel/userspace switch */
@@ -521,8 +590,18 @@ void sync_buffer(int cpu)
                        } else if (s->event == CPU_TRACE_BEGIN) {
                                state = sb_bt_start;
                                add_trace_begin();
+#ifdef CONFIG_OPROFILE_IBS
+                       } else if (s->event == IBS_FETCH_BEGIN) {
+                               state = sb_bt_start;
+                               add_ibs_begin(cpu_buf,
+                                       IBS_FETCH_CODE, in_kernel, mm);
+                       } else if (s->event == IBS_OP_BEGIN) {
+                               state = sb_bt_start;
+                               add_ibs_begin(cpu_buf,
+                                       IBS_OP_CODE, in_kernel, mm);
+#endif
                        } else {
-                               struct mm_struct * oldmm = mm;
+                               struct mm_struct *oldmm = mm;
 
                                /* userspace context switch */
                                new = (struct task_struct *)s->event;
@@ -533,13 +612,11 @@ void sync_buffer(int cpu)
                                        cookie = get_exec_dcookie(mm);
                                add_user_ctx_switch(new, cookie);
                        }
-               } else {
-                       if (state >= sb_bt_start &&
-                           !add_sample(mm, s, in_kernel)) {
-                               if (state == sb_bt_start) {
-                                       state = sb_bt_ignore;
-                                       atomic_inc(&oprofile_stats.bt_lost_no_mapping);
-                               }
+               } else if (state >= sb_bt_start &&
+                          !add_sample(mm, s, in_kernel)) {
+                       if (state == sb_bt_start) {
+                               state = sb_bt_ignore;
+                               atomic_inc(&oprofile_stats.bt_lost_no_mapping);
                        }
                }
 
index 7ba78e6d210e72ac9b41395ccc25fb6b4bfcd658..e1bd5a937f6c77d33ac1f92a16966e556c8bfff8 100644 (file)
@@ -5,6 +5,7 @@
  * @remark Read the file COPYING
  *
  * @author John Levon <levon@movementarian.org>
+ * @author Barry Kasindorf <barry.kasindorf@amd.com>
  *
  * Each CPU has a local buffer that stores PC value/event
  * pairs. We also log context switches when we notice them.
@@ -209,7 +210,7 @@ static int log_sample(struct oprofile_cpu_buffer * cpu_buf, unsigned long pc,
        return 1;
 }
 
-static int oprofile_begin_trace(struct oprofile_cpu_buffer * cpu_buf)
+static int oprofile_begin_trace(struct oprofile_cpu_buffer *cpu_buf)
 {
        if (nr_available_slots(cpu_buf) < 4) {
                cpu_buf->sample_lost_overflow++;
@@ -254,6 +255,75 @@ void oprofile_add_sample(struct pt_regs * const regs, unsigned long event)
        oprofile_add_ext_sample(pc, regs, event, is_kernel);
 }
 
+#ifdef CONFIG_OPROFILE_IBS
+
+#define MAX_IBS_SAMPLE_SIZE    14
+static int log_ibs_sample(struct oprofile_cpu_buffer *cpu_buf,
+       unsigned long pc, int is_kernel, unsigned  int *ibs, int ibs_code)
+{
+       struct task_struct *task;
+
+       cpu_buf->sample_received++;
+
+       if (nr_available_slots(cpu_buf) < MAX_IBS_SAMPLE_SIZE) {
+               cpu_buf->sample_lost_overflow++;
+               return 0;
+       }
+
+       is_kernel = !!is_kernel;
+
+       /* notice a switch from user->kernel or vice versa */
+       if (cpu_buf->last_is_kernel != is_kernel) {
+               cpu_buf->last_is_kernel = is_kernel;
+               add_code(cpu_buf, is_kernel);
+       }
+
+       /* notice a task switch */
+       if (!is_kernel) {
+               task = current;
+
+               if (cpu_buf->last_task != task) {
+                       cpu_buf->last_task = task;
+                       add_code(cpu_buf, (unsigned long)task);
+               }
+       }
+
+       add_code(cpu_buf, ibs_code);
+       add_sample(cpu_buf, ibs[0], ibs[1]);
+       add_sample(cpu_buf, ibs[2], ibs[3]);
+       add_sample(cpu_buf, ibs[4], ibs[5]);
+
+       if (ibs_code == IBS_OP_BEGIN) {
+       add_sample(cpu_buf, ibs[6], ibs[7]);
+       add_sample(cpu_buf, ibs[8], ibs[9]);
+       add_sample(cpu_buf, ibs[10], ibs[11]);
+       }
+
+       return 1;
+}
+
+void oprofile_add_ibs_sample(struct pt_regs *const regs,
+                               unsigned int * const ibs_sample, u8 code)
+{
+       int is_kernel = !user_mode(regs);
+       unsigned long pc = profile_pc(regs);
+
+       struct oprofile_cpu_buffer *cpu_buf =
+                        &per_cpu(cpu_buffer, smp_processor_id());
+
+       if (!backtrace_depth) {
+               log_ibs_sample(cpu_buf, pc, is_kernel, ibs_sample, code);
+               return;
+       }
+
+       /* if log_sample() fails we can't backtrace since we lost the source
+       * of this event */
+       if (log_ibs_sample(cpu_buf, pc, is_kernel, ibs_sample, code))
+               oprofile_ops.backtrace(regs, backtrace_depth);
+}
+
+#endif
+
 void oprofile_add_pc(unsigned long pc, int is_kernel, unsigned long event)
 {
        struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(cpu_buffer);
@@ -296,7 +366,7 @@ static void wq_sync_buffer(struct work_struct *work)
        struct oprofile_cpu_buffer * b =
                container_of(work, struct oprofile_cpu_buffer, work.work);
        if (b->cpu != smp_processor_id()) {
-               printk("WQ on CPU%d, prefer CPU%d\n",
+               printk(KERN_DEBUG "WQ on CPU%d, prefer CPU%d\n",
                       smp_processor_id(), b->cpu);
        }
        sync_buffer(b->cpu);
index c3e366b522619bd135964a17022638f4adfdec82..9c44d004da69c6a3747d5b9a4976be7f63c0d099 100644 (file)
@@ -55,5 +55,7 @@ void cpu_buffer_reset(struct oprofile_cpu_buffer * cpu_buf);
 /* transient events for the CPU buffer -> event buffer */
 #define CPU_IS_KERNEL 1
 #define CPU_TRACE_BEGIN 2
+#define IBS_FETCH_BEGIN 3
+#define IBS_OP_BEGIN    4
 
 #endif /* OPROFILE_CPU_BUFFER_H */
index d18e6d2e0b49dbac1f63d8a62483326ea7a1dea7..40759c33477d1d38bca2400f034affbf24e3efcc 100644 (file)
@@ -418,25 +418,22 @@ fs3270_open(struct inode *inode, struct file *filp)
 {
        struct fs3270 *fp;
        struct idal_buffer *ib;
-       int minor, rc;
+       int minor, rc = 0;
 
        if (imajor(filp->f_path.dentry->d_inode) != IBM_FS3270_MAJOR)
                return -ENODEV;
-       lock_kernel();
        minor = iminor(filp->f_path.dentry->d_inode);
        /* Check for minor 0 multiplexer. */
        if (minor == 0) {
-               struct tty_struct *tty;
-               mutex_lock(&tty_mutex);
-               tty = get_current_tty();
+               struct tty_struct *tty = get_current_tty();
                if (!tty || tty->driver->major != IBM_TTY3270_MAJOR) {
-                       mutex_unlock(&tty_mutex);
-                       rc = -ENODEV;
-                       goto out;
+                       tty_kref_put(tty);
+                       return -ENODEV;
                }
                minor = tty->index + RAW3270_FIRSTMINOR;
-               mutex_unlock(&tty_mutex);
+               tty_kref_put(tty);
        }
+       lock_kernel();
        /* Check if some other program is already using fullscreen mode. */
        fp = (struct fs3270 *) raw3270_find_view(&fs3270_fn, minor);
        if (!IS_ERR(fp)) {
@@ -478,7 +475,7 @@ fs3270_open(struct inode *inode, struct file *filp)
        filp->private_data = fp;
 out:
        unlock_kernel();
-       return 0;
+       return rc;
 }
 
 /*
index 9ccc563d87303604c8cd63f355040177c30faf81..d4104a3bbe87cd7400a68f083369c41da3396d5b 100644 (file)
 
 #include "8250.h"
 
+#ifdef CONFIG_SPARC
+#include "suncore.h"
+#endif
+
 /*
  * Configuration:
  *   share_irqs - whether we pass IRQF_SHARED to request_irq().  This option
@@ -53,6 +57,13 @@ static unsigned int share_irqs = SERIAL8250_SHARE_IRQS;
 
 static unsigned int nr_uarts = CONFIG_SERIAL_8250_RUNTIME_UARTS;
 
+static struct uart_driver serial8250_reg;
+
+static int serial_index(struct uart_port *port)
+{
+       return (serial8250_reg.minor - 64) + port->line;
+}
+
 /*
  * Debugging.
  */
@@ -536,7 +547,7 @@ static unsigned int serial_icr_read(struct uart_8250_port *up, int offset)
 /*
  * FIFO support.
  */
-static inline void serial8250_clear_fifos(struct uart_8250_port *p)
+static void serial8250_clear_fifos(struct uart_8250_port *p)
 {
        if (p->capabilities & UART_CAP_FIFO) {
                serial_outp(p, UART_FCR, UART_FCR_ENABLE_FIFO);
@@ -551,7 +562,7 @@ static inline void serial8250_clear_fifos(struct uart_8250_port *p)
  * capability" bit enabled.  Note that on XR16C850s, we need to
  * reset LCR to write to IER.
  */
-static inline void serial8250_set_sleep(struct uart_8250_port *p, int sleep)
+static void serial8250_set_sleep(struct uart_8250_port *p, int sleep)
 {
        if (p->capabilities & UART_CAP_SLEEP) {
                if (p->capabilities & UART_CAP_EFR) {
@@ -993,7 +1004,7 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
                return;
 
        DEBUG_AUTOCONF("ttyS%d: autoconf (0x%04x, 0x%p): ",
-                       up->port.line, up->port.iobase, up->port.membase);
+                      serial_index(&up->port), up->port.iobase, up->port.membase);
 
        /*
         * We really do need global IRQs disabled here - we're going to
@@ -1128,8 +1139,8 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
        if (up->capabilities != uart_config[up->port.type].flags) {
                printk(KERN_WARNING
                       "ttyS%d: detected caps %08x should be %08x\n",
-                       up->port.line, up->capabilities,
-                       uart_config[up->port.type].flags);
+                      serial_index(&up->port), up->capabilities,
+                      uart_config[up->port.type].flags);
        }
 
        up->port.fifosize = uart_config[up->port.type].fifo_size;
@@ -1424,8 +1435,7 @@ static unsigned int check_modem_status(struct uart_8250_port *up)
 /*
  * This handles the interrupt from one port.
  */
-static inline void
-serial8250_handle_port(struct uart_8250_port *up)
+static void serial8250_handle_port(struct uart_8250_port *up)
 {
        unsigned int status;
        unsigned long flags;
@@ -1719,7 +1729,7 @@ static void serial8250_break_ctl(struct uart_port *port, int break_state)
 /*
  *     Wait for transmitter & holding register to empty
  */
-static inline void wait_for_xmitr(struct uart_8250_port *up, int bits)
+static void wait_for_xmitr(struct uart_8250_port *up, int bits)
 {
        unsigned int status, tmout = 10000;
 
@@ -1854,7 +1864,8 @@ static int serial8250_startup(struct uart_port *port)
         */
        if (!(up->port.flags & UPF_BUGGY_UART) &&
            (serial_inp(up, UART_LSR) == 0xff)) {
-               printk("ttyS%d: LSR safety check engaged!\n", up->port.line);
+               printk(KERN_INFO "ttyS%d: LSR safety check engaged!\n",
+                      serial_index(&up->port));
                return -ENODEV;
        }
 
@@ -1909,7 +1920,8 @@ static int serial8250_startup(struct uart_port *port)
                 */
                if (!(iir1 & UART_IIR_NO_INT) && (iir & UART_IIR_NO_INT)) {
                        up->bugs |= UART_BUG_THRE;
-                       pr_debug("ttyS%d - using backup timer\n", port->line);
+                       pr_debug("ttyS%d - using backup timer\n",
+                                serial_index(port));
                }
        }
 
@@ -1969,7 +1981,7 @@ static int serial8250_startup(struct uart_port *port)
                if (!(up->bugs & UART_BUG_TXEN)) {
                        up->bugs |= UART_BUG_TXEN;
                        pr_debug("ttyS%d - enabling bad tx status workarounds\n",
-                                port->line);
+                                serial_index(port));
                }
        } else {
                up->bugs &= ~UART_BUG_TXEN;
@@ -2630,7 +2642,6 @@ static int serial8250_console_early_setup(void)
        return serial8250_find_port_for_earlycon();
 }
 
-static struct uart_driver serial8250_reg;
 static struct console serial8250_console = {
        .name           = "ttyS",
        .write          = serial8250_console_write,
@@ -2677,7 +2688,6 @@ static struct uart_driver serial8250_reg = {
        .dev_name               = "ttyS",
        .major                  = TTY_MAJOR,
        .minor                  = 64,
-       .nr                     = UART_NR,
        .cons                   = SERIAL8250_CONSOLE,
 };
 
@@ -2959,10 +2969,12 @@ static int __init serial8250_init(void)
                "%d ports, IRQ sharing %sabled\n", nr_uarts,
                share_irqs ? "en" : "dis");
 
-       for (i = 0; i < NR_IRQS; i++)
-               spin_lock_init(&irq_lists[i].lock);
-
+#ifdef CONFIG_SPARC
+       ret = sunserial_register_minors(&serial8250_reg, UART_NR);
+#else
+       serial8250_reg.nr = UART_NR;
        ret = uart_register_driver(&serial8250_reg);
+#endif
        if (ret)
                goto out;
 
@@ -2987,7 +2999,11 @@ static int __init serial8250_init(void)
  put_dev:
        platform_device_put(serial8250_isa_devs);
  unreg_uart_drv:
+#ifdef CONFIG_SPARC
+       sunserial_unregister_minors(&serial8250_reg, UART_NR);
+#else
        uart_unregister_driver(&serial8250_reg);
+#endif
  out:
        return ret;
 }
@@ -3006,7 +3022,11 @@ static void __exit serial8250_exit(void)
        platform_driver_unregister(&serial8250_isa_driver);
        platform_device_unregister(isa_dev);
 
+#ifdef CONFIG_SPARC
+       sunserial_unregister_minors(&serial8250_reg, UART_NR);
+#else
        uart_unregister_driver(&serial8250_reg);
+#endif
 }
 
 module_init(serial8250_init);
index c2f23933155b1cbfdff132b035f76d84b143a73a..c014ffb110e98c8b4801d47c4884ddead3a4b492 100644 (file)
@@ -2041,9 +2041,9 @@ static int pciserial_resume_one(struct pci_dev *dev)
                 * The device may have been disabled.  Re-enable it.
                 */
                err = pci_enable_device(dev);
+               /* FIXME: We cannot simply error out here */
                if (err)
-                       return err;
-
+                       printk(KERN_ERR "pciserial: Unable to re-enable ports, trying to continue.\n");
                pciserial_resume_ports(priv);
        }
        return 0;
index 77cb34270fc18699ad754c4d848bf27cc7e27942..31786b3b0a68673b0d4bba4a1711f4c05b3c5518 100644 (file)
@@ -9,7 +9,6 @@ menu "Serial drivers"
 # The new 8250/16550 serial drivers
 config SERIAL_8250
        tristate "8250/16550 and compatible serial support"
-       depends on (BROKEN || !SPARC)
        select SERIAL_CORE
        ---help---
          This selects whether you want to include the driver for the standard
@@ -994,24 +993,12 @@ config SERIAL_68328_RTS_CTS
        bool "Support RTS/CTS on 68328 serial port"
        depends on SERIAL_68328
 
-config SERIAL_COLDFIRE
-       bool "ColdFire serial support (DEPRECATED)"
-       depends on COLDFIRE
-       help
-         This driver supports the built-in serial ports of the Motorola ColdFire
-         family of CPUs.
-         This driver is deprecated because it supports only the old interface
-         for serial drivers and features like magic keys are not working.
-         Please switch to the new style driver because this driver will be
-         removed soon.
-
 config SERIAL_MCF
-       bool "Coldfire serial support (new style driver)"
+       bool "Coldfire serial support"
        depends on COLDFIRE
        select SERIAL_CORE
        help
-         This new serial driver supports the Freescale Coldfire serial ports
-         using the new serial driver subsystem.
+         This serial driver supports the Freescale Coldfire serial ports.
 
 config SERIAL_MCF_BAUDRATE
        int "Default baudrate for Coldfire serial ports"
index 7e7383e890d8b98c8b620252896ba9caf731f589..0c17c8ddb19d314be93614760224aed72e838e49 100644 (file)
@@ -4,6 +4,16 @@
 
 obj-$(CONFIG_SERIAL_CORE) += serial_core.o
 obj-$(CONFIG_SERIAL_21285) += 21285.o
+
+# These Sparc drivers have to appear before others such as 8250
+# which share ttySx minor node space.  Otherwise console device
+# names change and other unplesantries.
+obj-$(CONFIG_SERIAL_SUNCORE) += suncore.o
+obj-$(CONFIG_SERIAL_SUNHV) += sunhv.o
+obj-$(CONFIG_SERIAL_SUNZILOG) += sunzilog.o
+obj-$(CONFIG_SERIAL_SUNSU) += sunsu.o
+obj-$(CONFIG_SERIAL_SUNSAB) += sunsab.o
+
 obj-$(CONFIG_SERIAL_8250) += 8250.o
 obj-$(CONFIG_SERIAL_8250_PNP) += 8250_pnp.o
 obj-$(CONFIG_SERIAL_8250_GSC) += 8250_gsc.o
@@ -31,16 +41,10 @@ obj-$(CONFIG_SERIAL_S3C2400) += s3c2400.o
 obj-$(CONFIG_SERIAL_S3C2410) += s3c2410.o
 obj-$(CONFIG_SERIAL_S3C2412) += s3c2412.o
 obj-$(CONFIG_SERIAL_S3C2440) += s3c2440.o
-obj-$(CONFIG_SERIAL_SUNCORE) += suncore.o
-obj-$(CONFIG_SERIAL_SUNHV) += sunhv.o
-obj-$(CONFIG_SERIAL_SUNZILOG) += sunzilog.o
 obj-$(CONFIG_SERIAL_IP22_ZILOG) += ip22zilog.o
-obj-$(CONFIG_SERIAL_SUNSU) += sunsu.o
-obj-$(CONFIG_SERIAL_SUNSAB) += sunsab.o
 obj-$(CONFIG_SERIAL_MUX) += mux.o
 obj-$(CONFIG_SERIAL_68328) += 68328serial.o
 obj-$(CONFIG_SERIAL_68360) += 68360serial.o
-obj-$(CONFIG_SERIAL_COLDFIRE) += mcfserial.o
 obj-$(CONFIG_SERIAL_MCF) += mcf.o
 obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o
 obj-$(CONFIG_SERIAL_LH7A40X) += serial_lh7a40x.o
index 4a0d30bed9f12729355272560f66bff6aeb9649e..569f0e2476c690259e6234911db7c33c4998c4b9 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Blackfin On-Chip Serial Driver
  *
- * Copyright 2006-2007 Analog Devices Inc.
+ * Copyright 2006-2008 Analog Devices Inc.
  *
  * Enter bugs at http://blackfin.uclinux.org/
  *
@@ -42,6 +42,9 @@
 #define BFIN_SERIAL_MAJOR      204
 #define BFIN_SERIAL_MINOR      64
 
+static struct bfin_serial_port bfin_serial_ports[BFIN_UART_NR_PORTS];
+static int nr_active_ports = ARRAY_SIZE(bfin_serial_resource);
+
 /*
  * Setup for console. Argument comes from the menuconfig
  */
@@ -126,13 +129,13 @@ static int kgdb_entry_state;
 void kgdb_put_debug_char(int chr)
 {
        struct bfin_serial_port *uart;
-       
+
        if (CONFIG_KGDB_UART_PORT < 0
                || CONFIG_KGDB_UART_PORT >= BFIN_UART_NR_PORTS)
                uart = &bfin_serial_ports[0];
        else
                uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT];
-       
+
        while (!(UART_GET_LSR(uart) & THRE)) {
                SSYNC();
        }
@@ -152,7 +155,7 @@ int kgdb_get_debug_char(void)
                uart = &bfin_serial_ports[0];
        else
                uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT];
-       
+
        while(!(UART_GET_LSR(uart) & DR)) {
                SSYNC();
        }
@@ -298,7 +301,11 @@ static void bfin_serial_tx_chars(struct bfin_serial_port *uart)
        bfin_serial_mctrl_check(uart);
 
        if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) {
-               bfin_serial_stop_tx(&uart->port);
+#ifdef CONFIG_BF54x
+               /* Clear TFI bit */
+               UART_PUT_LSR(uart, TFI);
+#endif
+               UART_CLEAR_IER(uart, ETBEI);
                return;
        }
 
@@ -317,9 +324,6 @@ static void bfin_serial_tx_chars(struct bfin_serial_port *uart)
 
        if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
                uart_write_wakeup(&uart->port);
-
-       if (uart_circ_empty(xmit))
-               bfin_serial_stop_tx(&uart->port);
 }
 
 static irqreturn_t bfin_serial_rx_int(int irq, void *dev_id)
@@ -645,6 +649,42 @@ static int bfin_serial_startup(struct uart_port *port)
                free_irq(uart->port.irq, uart);
                return -EBUSY;
        }
+
+# ifdef CONFIG_BF54x
+       {
+               unsigned uart_dma_ch_rx, uart_dma_ch_tx;
+
+               switch (uart->port.irq) {
+               case IRQ_UART3_RX:
+                       uart_dma_ch_rx = CH_UART3_RX;
+                       uart_dma_ch_tx = CH_UART3_TX;
+                       break;
+               case IRQ_UART2_RX:
+                       uart_dma_ch_rx = CH_UART2_RX;
+                       uart_dma_ch_tx = CH_UART2_TX;
+                       break;
+               default:
+                       uart_dma_ch_rx = uart_dma_ch_tx = 0;
+                       break;
+               };
+
+               if (uart_dma_ch_rx &&
+                       request_dma(uart_dma_ch_rx, "BFIN_UART_RX") < 0) {
+                       printk(KERN_NOTICE"Fail to attach UART interrupt\n");
+                       free_irq(uart->port.irq, uart);
+                       free_irq(uart->port.irq + 1, uart);
+                       return -EBUSY;
+               }
+               if (uart_dma_ch_tx &&
+                       request_dma(uart_dma_ch_tx, "BFIN_UART_TX") < 0) {
+                       printk(KERN_NOTICE "Fail to attach UART interrupt\n");
+                       free_dma(uart_dma_ch_rx);
+                       free_irq(uart->port.irq, uart);
+                       free_irq(uart->port.irq + 1, uart);
+                       return -EBUSY;
+               }
+       }
+# endif
 #endif
        UART_SET_IER(uart, ERBFI);
        return 0;
@@ -662,6 +702,20 @@ static void bfin_serial_shutdown(struct uart_port *port)
        del_timer(&(uart->rx_dma_timer));
        dma_free_coherent(NULL, PAGE_SIZE, uart->rx_dma_buf.buf, 0);
 #else
+#ifdef CONFIG_BF54x
+       switch (uart->port.irq) {
+       case IRQ_UART3_RX:
+               free_dma(CH_UART3_RX);
+               free_dma(CH_UART3_TX);
+               break;
+       case IRQ_UART2_RX:
+               free_dma(CH_UART2_RX);
+               free_dma(CH_UART2_TX);
+               break;
+       default:
+               break;
+       };
+#endif
 #ifdef CONFIG_KGDB_UART
        if (uart->port.line != CONFIG_KGDB_UART_PORT)
 #endif
@@ -757,6 +811,9 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios,
        val |= UCEN;
        UART_PUT_GCTL(uart, val);
 
+       /* Port speed changed, update the per-port timeout. */
+       uart_update_timeout(port, termios->c_cflag, baud);
+
        spin_unlock_irqrestore(&uart->port.lock, flags);
 }
 
@@ -859,8 +916,9 @@ static void __init bfin_serial_init_ports(void)
                return;
        first = 0;
 
-       for (i = 0; i < nr_ports; i++) {
+       for (i = 0; i < nr_active_ports; i++) {
                bfin_serial_ports[i].port.uartclk   = get_sclk();
+               bfin_serial_ports[i].port.fifosize  = BFIN_UART_TX_FIFO_SIZE;
                bfin_serial_ports[i].port.ops       = &bfin_serial_pops;
                bfin_serial_ports[i].port.line      = i;
                bfin_serial_ports[i].port.iotype    = UPIO_MEM;
@@ -961,7 +1019,7 @@ bfin_serial_console_setup(struct console *co, char *options)
         * if so, search for the first available port that does have
         * console support.
         */
-       if (co->index == -1 || co->index >= nr_ports)
+       if (co->index == -1 || co->index >= nr_active_ports)
                co->index = 0;
        uart = &bfin_serial_ports[co->index];
 
@@ -1056,7 +1114,7 @@ static __init void early_serial_write(struct console *con, const char *s,
        }
 }
 
-static struct __init console bfin_early_serial_console = {
+static struct __initdata console bfin_early_serial_console = {
        .name = "early_BFuart",
        .write = early_serial_write,
        .device = uart_console_device,
@@ -1072,7 +1130,7 @@ struct console __init *bfin_earlyserial_init(unsigned int port,
        struct bfin_serial_port *uart;
        struct ktermios t;
 
-       if (port == -1 || port >= nr_ports)
+       if (port == -1 || port >= nr_active_ports)
                port = 0;
        bfin_serial_init_ports();
        bfin_early_serial_console.index = port;
@@ -1100,20 +1158,26 @@ static struct uart_driver bfin_serial_reg = {
 
 static int bfin_serial_suspend(struct platform_device *dev, pm_message_t state)
 {
-       struct bfin_serial_port *uart = platform_get_drvdata(dev);
+       int i;
 
-       if (uart)
-               uart_suspend_port(&bfin_serial_reg, &uart->port);
+       for (i = 0; i < nr_active_ports; i++) {
+               if (bfin_serial_ports[i].port.dev != &dev->dev)
+                       continue;
+               uart_suspend_port(&bfin_serial_reg, &bfin_serial_ports[i].port);
+       }
 
        return 0;
 }
 
 static int bfin_serial_resume(struct platform_device *dev)
 {
-       struct bfin_serial_port *uart = platform_get_drvdata(dev);
+       int i;
 
-       if (uart)
-               uart_resume_port(&bfin_serial_reg, &uart->port);
+       for (i = 0; i < nr_active_ports; i++) {
+               if (bfin_serial_ports[i].port.dev != &dev->dev)
+                       continue;
+               uart_resume_port(&bfin_serial_reg, &bfin_serial_ports[i].port);
+       }
 
        return 0;
 }
@@ -1128,32 +1192,31 @@ static int bfin_serial_probe(struct platform_device *dev)
                        break;
 
        if (i < dev->num_resources) {
-               for (i = 0; i < nr_ports; i++, res++) {
+               for (i = 0; i < nr_active_ports; i++, res++) {
                        if (bfin_serial_ports[i].port.mapbase != res->start)
                                continue;
                        bfin_serial_ports[i].port.dev = &dev->dev;
                        uart_add_one_port(&bfin_serial_reg, &bfin_serial_ports[i].port);
-                       platform_set_drvdata(dev, &bfin_serial_ports[i]);
                }
        }
 
        return 0;
 }
 
-static int bfin_serial_remove(struct platform_device *pdev)
+static int bfin_serial_remove(struct platform_device *dev)
 {
-       struct bfin_serial_port *uart = platform_get_drvdata(pdev);
-
+       int i;
 
+       for (i = 0; i < nr_active_ports; i++) {
+               if (bfin_serial_ports[i].port.dev != &dev->dev)
+                       continue;
+               uart_remove_one_port(&bfin_serial_reg, &bfin_serial_ports[i].port);
+               bfin_serial_ports[i].port.dev = NULL;
 #ifdef CONFIG_SERIAL_BFIN_CTSRTS
-       gpio_free(uart->cts_pin);
-       gpio_free(uart->rts_pin);
+               gpio_free(bfin_serial_ports[i].cts_pin);
+               gpio_free(bfin_serial_ports[i].rts_pin);
 #endif
-
-       platform_set_drvdata(pdev, NULL);
-
-       if (uart)
-               uart_remove_one_port(&bfin_serial_reg, &uart->port);
+       }
 
        return 0;
 }
index bf94a770bb445d4b2d13ed71865f18fb982bfb0e..211c21797ce016ef8646a8c04a32f5affd35ed17 100644 (file)
@@ -457,7 +457,6 @@ static struct e100_serial rs_table[] = {
 #define NR_PORTS (sizeof(rs_table)/sizeof(struct e100_serial))
 
 static struct ktermios *serial_termios[NR_PORTS];
-static struct ktermios *serial_termios_locked[NR_PORTS];
 #ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
 static struct fast_timer fast_timers[NR_PORTS];
 #endif
@@ -4419,6 +4418,7 @@ rs_init(void)
                        rs485_pa_bit)) {
                printk(KERN_CRIT "ETRAX100LX serial: Could not allocate "
                        "RS485 pin\n");
+               put_tty_driver(driver);
                return -EBUSY;
        }
 #endif
@@ -4427,6 +4427,7 @@ rs_init(void)
                        rs485_port_g_bit)) {
                printk(KERN_CRIT "ETRAX100LX serial: Could not allocate "
                        "RS485 pin\n");
+               put_tty_driver(driver);
                return -EBUSY;
        }
 #endif
@@ -4446,8 +4447,6 @@ rs_init(void)
        driver->init_termios.c_ispeed = 115200;
        driver->init_termios.c_ospeed = 115200;
        driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
-       driver->termios = serial_termios;
-       driver->termios_locked = serial_termios_locked;
 
        tty_set_operations(driver, &rs_ops);
         serial_driver = driver;
diff --git a/drivers/serial/mcfserial.c b/drivers/serial/mcfserial.c
deleted file mode 100644 (file)
index fbe3835..0000000
+++ /dev/null
@@ -1,1965 +0,0 @@
-#warning This driver is deprecated. Check Kconfig for details.
-/*
- * mcfserial.c -- serial driver for ColdFire internal UARTS.
- *
- * Copyright (C) 1999-2003 Greg Ungerer <gerg@snapgear.com>
- * Copyright (c) 2000-2001 Lineo, Inc. <www.lineo.com> 
- * Copyright (C) 2001-2002 SnapGear Inc. <www.snapgear.com> 
- *
- * Based on code from 68332serial.c which was:
- *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1998 TSHG
- * Copyright (c) 1999 Rt-Control Inc. <jeff@uclinux.org>
- *
- * Changes:
- * 08/07/2003    Daniele Bellucci <bellucda@tiscali.it>
- *               some cleanups in mcfrs_write.
- *
- */
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/wait.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/string.h>
-#include <linux/fcntl.h>
-#include <linux/mm.h>
-#include <linux/kernel.h>
-#include <linux/serial.h>
-#include <linux/serialP.h>
-#include <linux/console.h>
-#include <linux/init.h>
-#include <linux/bitops.h>
-#include <linux/delay.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-#include <asm/delay.h>
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-#include <asm/mcfuart.h>
-#include <asm/nettel.h>
-#include <asm/uaccess.h>
-#include "mcfserial.h"
-
-struct timer_list mcfrs_timer_struct;
-
-/*
- *     Default console baud rate,  we use this as the default
- *     for all ports so init can just open /dev/console and
- *     keep going.  Perhaps one day the cflag settings for the
- *     console can be used instead.
- */
-#if defined(CONFIG_HW_FEITH)
-#define        CONSOLE_BAUD_RATE       38400
-#define        DEFAULT_CBAUD           B38400
-#elif defined(CONFIG_MOD5272) || defined(CONFIG_M5208EVB) || \
-      defined(CONFIG_M5329EVB) || defined(CONFIG_GILBARCO)
-#define CONSOLE_BAUD_RATE      115200
-#define DEFAULT_CBAUD          B115200
-#elif defined(CONFIG_ARNEWSH) || defined(CONFIG_FREESCALE) || \
-      defined(CONFIG_senTec) || defined(CONFIG_SNEHA) || defined(CONFIG_AVNET)
-#define        CONSOLE_BAUD_RATE       19200
-#define        DEFAULT_CBAUD           B19200
-#endif
-
-#ifndef CONSOLE_BAUD_RATE
-#define        CONSOLE_BAUD_RATE       9600
-#define        DEFAULT_CBAUD           B9600
-#endif
-
-int mcfrs_console_inited = 0;
-int mcfrs_console_port = -1;
-int mcfrs_console_baud = CONSOLE_BAUD_RATE;
-int mcfrs_console_cbaud = DEFAULT_CBAUD;
-
-/*
- *     Driver data structures.
- */
-static struct tty_driver *mcfrs_serial_driver;
-
-/* number of characters left in xmit buffer before we ask for more */
-#define WAKEUP_CHARS 256
-
-/* Debugging...
- */
-#undef SERIAL_DEBUG_OPEN
-#undef SERIAL_DEBUG_FLOW
-
-#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \
-    defined(CONFIG_M520x) || defined(CONFIG_M532x)
-#define        IRQBASE (MCFINT_VECBASE+MCFINT_UART0)
-#else
-#define        IRQBASE 73
-#endif
-
-/*
- *     Configuration table, UARTs to look for at startup.
- */
-static struct mcf_serial mcfrs_table[] = {
-       {  /* ttyS0 */
-               .magic = 0,
-               .addr = (volatile unsigned char *) (MCF_MBAR+MCFUART_BASE1),
-               .irq = IRQBASE,
-               .flags = ASYNC_BOOT_AUTOCONF,
-       },
-#ifdef MCFUART_BASE2
-       {  /* ttyS1 */
-               .magic = 0,
-               .addr = (volatile unsigned char *) (MCF_MBAR+MCFUART_BASE2),
-               .irq = IRQBASE+1,
-               .flags = ASYNC_BOOT_AUTOCONF,
-       },
-#endif
-#ifdef MCFUART_BASE3
-       {  /* ttyS2 */
-               .magic = 0,
-               .addr = (volatile unsigned char *) (MCF_MBAR+MCFUART_BASE3),
-               .irq = IRQBASE+2,
-               .flags = ASYNC_BOOT_AUTOCONF,
-       },
-#endif
-#ifdef MCFUART_BASE4
-       {  /* ttyS3 */
-               .magic = 0,
-               .addr = (volatile unsigned char *) (MCF_MBAR+MCFUART_BASE4),
-               .irq = IRQBASE+3,
-               .flags = ASYNC_BOOT_AUTOCONF,
-       },
-#endif
-};
-
-
-#define        NR_PORTS        (sizeof(mcfrs_table) / sizeof(struct mcf_serial))
-
-/*
- * This is used to figure out the divisor speeds and the timeouts.
- */
-static int mcfrs_baud_table[] = {
-       0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
-       9600, 19200, 38400, 57600, 115200, 230400, 460800, 0
-};
-#define MCFRS_BAUD_TABLE_SIZE \
-                       (sizeof(mcfrs_baud_table)/sizeof(mcfrs_baud_table[0]))
-
-
-#ifdef CONFIG_MAGIC_SYSRQ
-/*
- *     Magic system request keys. Used for debugging...
- */
-extern int     magic_sysrq_key(int ch);
-#endif
-
-
-/*
- *     Forware declarations...
- */
-static void    mcfrs_change_speed(struct mcf_serial *info);
-static void    mcfrs_wait_until_sent(struct tty_struct *tty, int timeout);
-
-
-static inline int serial_paranoia_check(struct mcf_serial *info,
-                                       char *name, const char *routine)
-{
-#ifdef SERIAL_PARANOIA_CHECK
-       static const char badmagic[] =
-               "MCFRS(warning): bad magic number for serial struct %s in %s\n";
-       static const char badinfo[] =
-               "MCFRS(warning): null mcf_serial for %s in %s\n";
-
-       if (!info) {
-               printk(badinfo, name, routine);
-               return 1;
-       }
-       if (info->magic != SERIAL_MAGIC) {
-               printk(badmagic, name, routine);
-               return 1;
-       }
-#endif
-       return 0;
-}
-
-/*
- *     Sets or clears DTR and RTS on the requested line.
- */
-static void mcfrs_setsignals(struct mcf_serial *info, int dtr, int rts)
-{
-       volatile unsigned char  *uartp;
-       unsigned long           flags;
-       
-#if 0
-       printk("%s(%d): mcfrs_setsignals(info=%x,dtr=%d,rts=%d)\n",
-               __FILE__, __LINE__, info, dtr, rts);
-#endif
-
-       local_irq_save(flags);
-       if (dtr >= 0) {
-#ifdef MCFPP_DTR0
-               if (info->line)
-                       mcf_setppdata(MCFPP_DTR1, (dtr ? 0 : MCFPP_DTR1));
-               else
-                       mcf_setppdata(MCFPP_DTR0, (dtr ? 0 : MCFPP_DTR0));
-#endif
-       }
-       if (rts >= 0) {
-               uartp = info->addr;
-               if (rts) {
-                       info->sigs |= TIOCM_RTS;
-                       uartp[MCFUART_UOP1] = MCFUART_UOP_RTS;
-               } else {
-                       info->sigs &= ~TIOCM_RTS;
-                       uartp[MCFUART_UOP0] = MCFUART_UOP_RTS;
-               }
-       }
-       local_irq_restore(flags);
-       return;
-}
-
-/*
- *     Gets values of serial signals.
- */
-static int mcfrs_getsignals(struct mcf_serial *info)
-{
-       volatile unsigned char  *uartp;
-       unsigned long           flags;
-       int                     sigs;
-#if defined(CONFIG_NETtel) && defined(CONFIG_M5307)
-       unsigned short          ppdata;
-#endif
-
-#if 0
-       printk("%s(%d): mcfrs_getsignals(info=%x)\n", __FILE__, __LINE__);
-#endif
-
-       local_irq_save(flags);
-       uartp = info->addr;
-       sigs = (uartp[MCFUART_UIPR] & MCFUART_UIPR_CTS) ? 0 : TIOCM_CTS;
-       sigs |= (info->sigs & TIOCM_RTS);
-
-#ifdef MCFPP_DCD0
-{
-       unsigned int ppdata;
-       ppdata = mcf_getppdata();
-       if (info->line == 0) {
-               sigs |= (ppdata & MCFPP_DCD0) ? 0 : TIOCM_CD;
-               sigs |= (ppdata & MCFPP_DTR0) ? 0 : TIOCM_DTR;
-       } else if (info->line == 1) {
-               sigs |= (ppdata & MCFPP_DCD1) ? 0 : TIOCM_CD;
-               sigs |= (ppdata & MCFPP_DTR1) ? 0 : TIOCM_DTR;
-       }
-}
-#endif
-
-       local_irq_restore(flags);
-       return(sigs);
-}
-
-/*
- * ------------------------------------------------------------
- * mcfrs_stop() and mcfrs_start()
- *
- * This routines are called before setting or resetting tty->stopped.
- * They enable or disable transmitter interrupts, as necessary.
- * ------------------------------------------------------------
- */
-static void mcfrs_stop(struct tty_struct *tty)
-{
-       volatile unsigned char  *uartp;
-       struct mcf_serial       *info = (struct mcf_serial *)tty->driver_data;
-       unsigned long           flags;
-
-       if (serial_paranoia_check(info, tty->name, "mcfrs_stop"))
-               return;
-       
-       local_irq_save(flags);
-       uartp = info->addr;
-       info->imr &= ~MCFUART_UIR_TXREADY;
-       uartp[MCFUART_UIMR] = info->imr;
-       local_irq_restore(flags);
-}
-
-static void mcfrs_start(struct tty_struct *tty)
-{
-       volatile unsigned char  *uartp;
-       struct mcf_serial       *info = (struct mcf_serial *)tty->driver_data;
-       unsigned long           flags;
-       
-       if (serial_paranoia_check(info, tty->name, "mcfrs_start"))
-               return;
-
-       local_irq_save(flags);
-       if (info->xmit_cnt && info->xmit_buf) {
-               uartp = info->addr;
-               info->imr |= MCFUART_UIR_TXREADY;
-               uartp[MCFUART_UIMR] = info->imr;
-       }
-       local_irq_restore(flags);
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * Here starts the interrupt handling routines.  All of the following
- * subroutines are declared as inline and are folded into
- * mcfrs_interrupt().  They were separated out for readability's sake.
- *
- * Note: mcfrs_interrupt() is a "fast" interrupt, which means that it
- * runs with interrupts turned off.  People who may want to modify
- * mcfrs_interrupt() should try to keep the interrupt handler as fast as
- * possible.  After you are done making modifications, it is not a bad
- * idea to do:
- * 
- * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c
- *
- * and look at the resulting assemble code in serial.s.
- *
- *                             - Ted Ts'o (tytso@mit.edu), 7-Mar-93
- * -----------------------------------------------------------------------
- */
-
-static inline void receive_chars(struct mcf_serial *info)
-{
-       volatile unsigned char  *uartp;
-       struct tty_struct       *tty = info->port.tty;
-       unsigned char           status, ch, flag;
-
-       if (!tty)
-               return;
-
-       uartp = info->addr;
-
-       while ((status = uartp[MCFUART_USR]) & MCFUART_USR_RXREADY) {
-               ch = uartp[MCFUART_URB];
-               info->stats.rx++;
-
-#ifdef CONFIG_MAGIC_SYSRQ
-               if (mcfrs_console_inited && (info->line == mcfrs_console_port)) {
-                       if (magic_sysrq_key(ch))
-                               continue;
-               }
-#endif
-
-               flag = TTY_NORMAL;
-               if (status & MCFUART_USR_RXERR) {
-                       uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETERR;
-                       if (status & MCFUART_USR_RXBREAK) {
-                               info->stats.rxbreak++;
-                               flag = TTY_BREAK;
-                       } else if (status & MCFUART_USR_RXPARITY) {
-                               info->stats.rxparity++;
-                               flag = TTY_PARITY;
-                       } else if (status & MCFUART_USR_RXOVERRUN) {
-                               info->stats.rxoverrun++;
-                               flag = TTY_OVERRUN;
-                       } else if (status & MCFUART_USR_RXFRAMING) {
-                               info->stats.rxframing++;
-                               flag = TTY_FRAME;
-                       }
-               }
-               tty_insert_flip_char(tty, ch, flag);
-       }
-       tty_schedule_flip(tty);
-       return;
-}
-
-static inline void transmit_chars(struct mcf_serial *info)
-{
-       volatile unsigned char  *uartp;
-
-       uartp = info->addr;
-
-       if (info->x_char) {
-               /* Send special char - probably flow control */
-               uartp[MCFUART_UTB] = info->x_char;
-               info->x_char = 0;
-               info->stats.tx++;
-       }
-
-       if ((info->xmit_cnt <= 0) || info->port.tty->stopped) {
-               info->imr &= ~MCFUART_UIR_TXREADY;
-               uartp[MCFUART_UIMR] = info->imr;
-               return;
-       }
-
-       while (uartp[MCFUART_USR] & MCFUART_USR_TXREADY) {
-               uartp[MCFUART_UTB] = info->xmit_buf[info->xmit_tail++];
-               info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
-               info->stats.tx++;
-               if (--info->xmit_cnt <= 0)
-                       break;
-       }
-
-       if (info->xmit_cnt < WAKEUP_CHARS)
-               schedule_work(&info->tqueue);
-       return;
-}
-
-/*
- * This is the serial driver's generic interrupt routine
- */
-irqreturn_t mcfrs_interrupt(int irq, void *dev_id)
-{
-       struct mcf_serial       *info;
-       unsigned char           isr;
-
-       info = &mcfrs_table[(irq - IRQBASE)];
-       isr = info->addr[MCFUART_UISR] & info->imr;
-
-       if (isr & MCFUART_UIR_RXREADY)
-               receive_chars(info);
-       if (isr & MCFUART_UIR_TXREADY)
-               transmit_chars(info);
-       return IRQ_HANDLED;
-}
-
-/*
- * -------------------------------------------------------------------
- * Here ends the serial interrupt routines.
- * -------------------------------------------------------------------
- */
-
-static void mcfrs_offintr(struct work_struct *work)
-{
-       struct mcf_serial *info = container_of(work, struct mcf_serial, tqueue);
-       struct tty_struct *tty = info->port.tty;
-       
-       if (tty)
-               tty_wakeup(tty);
-}
-
-
-/*
- *     Change of state on a DCD line.
- */
-void mcfrs_modem_change(struct mcf_serial *info, int dcd)
-{
-       if (info->count == 0)
-               return;
-
-       if (info->flags & ASYNC_CHECK_CD) {
-               if (dcd)
-                       wake_up_interruptible(&info->open_wait);
-               else 
-                       schedule_work(&info->tqueue_hangup);
-       }
-}
-
-
-#ifdef MCFPP_DCD0
-
-unsigned short mcfrs_ppstatus;
-
-/*
- * This subroutine is called when the RS_TIMER goes off. It is used
- * to monitor the state of the DCD lines - since they have no edge
- * sensors and interrupt generators.
- */
-static void mcfrs_timer(void)
-{
-       unsigned int    ppstatus, dcdval, i;
-
-       ppstatus = mcf_getppdata() & (MCFPP_DCD0 | MCFPP_DCD1);
-
-       if (ppstatus != mcfrs_ppstatus) {
-               for (i = 0; (i < 2); i++) {
-                       dcdval = (i ? MCFPP_DCD1 : MCFPP_DCD0);
-                       if ((ppstatus & dcdval) != (mcfrs_ppstatus & dcdval)) {
-                               mcfrs_modem_change(&mcfrs_table[i],
-                                       ((ppstatus & dcdval) ? 0 : 1));
-                       }
-               }
-       }
-       mcfrs_ppstatus = ppstatus;
-
-       /* Re-arm timer */
-       mcfrs_timer_struct.expires = jiffies + HZ/25;
-       add_timer(&mcfrs_timer_struct);
-}
-
-#endif /* MCFPP_DCD0 */
-
-
-/*
- * This routine is called from the scheduler tqueue when the interrupt
- * routine has signalled that a hangup has occurred. The path of
- * hangup processing is:
- *
- *     serial interrupt routine -> (scheduler tqueue) ->
- *     do_serial_hangup() -> tty->hangup() -> mcfrs_hangup()
- * 
- */
-static void do_serial_hangup(struct work_struct *work)
-{
-       struct mcf_serial *info = container_of(work, struct mcf_serial, tqueue_hangup);
-       struct tty_struct *tty = info->port.tty;
-       
-       if (tty)
-               tty_hangup(tty);
-}
-
-static int startup(struct mcf_serial * info)
-{
-       volatile unsigned char  *uartp;
-       unsigned long           flags;
-       
-       if (info->flags & ASYNC_INITIALIZED)
-               return 0;
-
-       if (!info->xmit_buf) {
-               info->xmit_buf = (unsigned char *) __get_free_page(GFP_KERNEL);
-               if (!info->xmit_buf)
-                       return -ENOMEM;
-       }
-
-       local_irq_save(flags);
-
-#ifdef SERIAL_DEBUG_OPEN
-       printk("starting up ttyS%d (irq %d)...\n", info->line, info->irq);
-#endif
-
-       /*
-        *      Reset UART, get it into known state...
-        */
-       uartp = info->addr;
-       uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETRX;  /* reset RX */
-       uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETTX;  /* reset TX */
-       mcfrs_setsignals(info, 1, 1);
-
-       if (info->port.tty)
-               clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
-       info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
-
-       /*
-        * and set the speed of the serial port
-        */
-       mcfrs_change_speed(info);
-
-       /*
-        * Lastly enable the UART transmitter and receiver, and
-        * interrupt enables.
-        */
-       info->imr = MCFUART_UIR_RXREADY;
-       uartp[MCFUART_UCR] = MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE;
-       uartp[MCFUART_UIMR] = info->imr;
-
-       info->flags |= ASYNC_INITIALIZED;
-       local_irq_restore(flags);
-       return 0;
-}
-
-/*
- * This routine will shutdown a serial port; interrupts are disabled, and
- * DTR is dropped if the hangup on close termio flag is on.
- */
-static void shutdown(struct mcf_serial * info)
-{
-       volatile unsigned char  *uartp;
-       unsigned long           flags;
-
-       if (!(info->flags & ASYNC_INITIALIZED))
-               return;
-
-#ifdef SERIAL_DEBUG_OPEN
-       printk("Shutting down serial port %d (irq %d)....\n", info->line,
-              info->irq);
-#endif
-       
-       local_irq_save(flags);
-
-       uartp = info->addr;
-       uartp[MCFUART_UIMR] = 0;  /* mask all interrupts */
-       uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETRX;  /* reset RX */
-       uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETTX;  /* reset TX */
-
-       if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL))
-               mcfrs_setsignals(info, 0, 0);
-
-       if (info->xmit_buf) {
-               free_page((unsigned long) info->xmit_buf);
-               info->xmit_buf = 0;
-       }
-
-       if (info->port.tty)
-               set_bit(TTY_IO_ERROR, &info->port.tty->flags);
-       
-       info->flags &= ~ASYNC_INITIALIZED;
-       local_irq_restore(flags);
-}
-
-
-/*
- * This routine is called to set the UART divisor registers to match
- * the specified baud rate for a serial port.
- */
-static void mcfrs_change_speed(struct mcf_serial *info)
-{
-       volatile unsigned char  *uartp;
-       unsigned int            baudclk, cflag;
-       unsigned long           flags;
-       unsigned char           mr1, mr2;
-       int                     i;
-#ifdef CONFIG_M5272
-       unsigned int            fraction;
-#endif
-
-       if (!info->port.tty || !info->port.tty->termios)
-               return;
-       cflag = info->port.tty->termios->c_cflag;
-       if (info->addr == 0)
-               return;
-
-#if 0
-       printk("%s(%d): mcfrs_change_speed()\n", __FILE__, __LINE__);
-#endif
-
-       i = cflag & CBAUD;
-       if (i & CBAUDEX) {
-               i &= ~CBAUDEX;
-               if (i < 1 || i > 4)
-                       info->port.tty->termios->c_cflag &= ~CBAUDEX;
-               else
-                       i += 15;
-       }
-       if (i == 0) {
-               mcfrs_setsignals(info, 0, -1);
-               return;
-       }
-
-       /* compute the baudrate clock */
-#ifdef CONFIG_M5272
-       /*
-        * For the MCF5272, also compute the baudrate fraction.
-        */
-       baudclk = (MCF_BUSCLK / mcfrs_baud_table[i]) / 32;
-       fraction = MCF_BUSCLK - (baudclk * 32 * mcfrs_baud_table[i]);
-       fraction *= 16;
-       fraction /= (32 * mcfrs_baud_table[i]);
-#else
-       baudclk = ((MCF_BUSCLK / mcfrs_baud_table[i]) + 16) / 32;
-#endif
-
-       info->baud = mcfrs_baud_table[i];
-
-       mr1 = MCFUART_MR1_RXIRQRDY | MCFUART_MR1_RXERRCHAR;
-       mr2 = 0;
-
-       switch (cflag & CSIZE) {
-       case CS5:       mr1 |= MCFUART_MR1_CS5; break;
-       case CS6:       mr1 |= MCFUART_MR1_CS6; break;
-       case CS7:       mr1 |= MCFUART_MR1_CS7; break;
-       case CS8:
-       default:        mr1 |= MCFUART_MR1_CS8; break;
-       }
-
-       if (cflag & PARENB) {
-               if (cflag & CMSPAR) {
-                       if (cflag & PARODD)
-                               mr1 |= MCFUART_MR1_PARITYMARK;
-                       else
-                               mr1 |= MCFUART_MR1_PARITYSPACE;
-               } else {
-                       if (cflag & PARODD)
-                               mr1 |= MCFUART_MR1_PARITYODD;
-                       else
-                               mr1 |= MCFUART_MR1_PARITYEVEN;
-               }
-       } else {
-               mr1 |= MCFUART_MR1_PARITYNONE;
-       }
-
-       if (cflag & CSTOPB)
-               mr2 |= MCFUART_MR2_STOP2;
-       else
-               mr2 |= MCFUART_MR2_STOP1;
-
-       if (cflag & CRTSCTS) {
-               mr1 |= MCFUART_MR1_RXRTS;
-               mr2 |= MCFUART_MR2_TXCTS;
-       }
-
-       if (cflag & CLOCAL)
-               info->flags &= ~ASYNC_CHECK_CD;
-       else
-               info->flags |= ASYNC_CHECK_CD;
-
-       uartp = info->addr;
-
-       local_irq_save(flags);
-#if 0
-       printk("%s(%d): mr1=%x mr2=%x baudclk=%x\n", __FILE__, __LINE__,
-               mr1, mr2, baudclk);
-#endif
-       /*
-         Note: pg 12-16 of MCF5206e User's Manual states that a
-         software reset should be performed prior to changing
-         UMR1,2, UCSR, UACR, bit 7
-       */
-       uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETRX;    /* reset RX */
-       uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETTX;    /* reset TX */
-       uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETMRPTR; /* reset MR pointer */
-       uartp[MCFUART_UMR] = mr1;
-       uartp[MCFUART_UMR] = mr2;
-       uartp[MCFUART_UBG1] = (baudclk & 0xff00) >> 8;  /* set msb byte */
-       uartp[MCFUART_UBG2] = (baudclk & 0xff);         /* set lsb byte */
-#ifdef CONFIG_M5272
-       uartp[MCFUART_UFPD] = (fraction & 0xf);         /* set fraction */
-#endif
-       uartp[MCFUART_UCSR] = MCFUART_UCSR_RXCLKTIMER | MCFUART_UCSR_TXCLKTIMER;
-       uartp[MCFUART_UCR] = MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE;
-       mcfrs_setsignals(info, 1, -1);
-       local_irq_restore(flags);
-       return;
-}
-
-static void mcfrs_flush_chars(struct tty_struct *tty)
-{
-       volatile unsigned char  *uartp;
-       struct mcf_serial       *info = (struct mcf_serial *)tty->driver_data;
-       unsigned long           flags;
-
-       if (serial_paranoia_check(info, tty->name, "mcfrs_flush_chars"))
-               return;
-
-       uartp = (volatile unsigned char *) info->addr;
-
-       /*
-        * re-enable receiver interrupt
-        */
-       local_irq_save(flags);
-       if ((!(info->imr & MCFUART_UIR_RXREADY)) &&
-           (info->flags & ASYNC_INITIALIZED) ) {
-               info->imr |= MCFUART_UIR_RXREADY;
-               uartp[MCFUART_UIMR] = info->imr;
-       }
-       local_irq_restore(flags);
-
-       if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
-           !info->xmit_buf)
-               return;
-
-       /* Enable transmitter */
-       local_irq_save(flags);
-       info->imr |= MCFUART_UIR_TXREADY;
-       uartp[MCFUART_UIMR] = info->imr;
-       local_irq_restore(flags);
-}
-
-static int mcfrs_write(struct tty_struct * tty,
-                   const unsigned char *buf, int count)
-{
-       volatile unsigned char  *uartp;
-       struct mcf_serial       *info = (struct mcf_serial *)tty->driver_data;
-       unsigned long           flags;
-       int                     c, total = 0;
-
-#if 0
-       printk("%s(%d): mcfrs_write(tty=%x,buf=%x,count=%d)\n",
-               __FILE__, __LINE__, (int)tty, (int)buf, count);
-#endif
-
-       if (serial_paranoia_check(info, tty->name, "mcfrs_write"))
-               return 0;
-
-       if (!tty || !info->xmit_buf)
-               return 0;
-       
-       local_save_flags(flags);
-       while (1) {
-               local_irq_disable();            
-               c = min(count, (int) min(((int)SERIAL_XMIT_SIZE) - info->xmit_cnt - 1,
-                       ((int)SERIAL_XMIT_SIZE) - info->xmit_head));
-               local_irq_restore(flags);
-
-               if (c <= 0)
-                       break;
-
-               memcpy(info->xmit_buf + info->xmit_head, buf, c);
-
-               local_irq_disable();
-               info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
-               info->xmit_cnt += c;
-               local_irq_restore(flags);
-
-               buf += c;
-               count -= c;
-               total += c;
-       }
-
-       local_irq_disable();
-       uartp = info->addr;
-       info->imr |= MCFUART_UIR_TXREADY;
-       uartp[MCFUART_UIMR] = info->imr;
-       local_irq_restore(flags);
-
-       return total;
-}
-
-static int mcfrs_write_room(struct tty_struct *tty)
-{
-       struct mcf_serial *info = (struct mcf_serial *)tty->driver_data;
-       int     ret;
-
-       if (serial_paranoia_check(info, tty->name, "mcfrs_write_room"))
-               return 0;
-       ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
-       if (ret < 0)
-               ret = 0;
-       return ret;
-}
-
-static int mcfrs_chars_in_buffer(struct tty_struct *tty)
-{
-       struct mcf_serial *info = (struct mcf_serial *)tty->driver_data;
-
-       if (serial_paranoia_check(info, tty->name, "mcfrs_chars_in_buffer"))
-               return 0;
-       return info->xmit_cnt;
-}
-
-static void mcfrs_flush_buffer(struct tty_struct *tty)
-{
-       struct mcf_serial       *info = (struct mcf_serial *)tty->driver_data;
-       unsigned long           flags;
-
-       if (serial_paranoia_check(info, tty->name, "mcfrs_flush_buffer"))
-               return;
-
-       local_irq_save(flags);
-       info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
-       local_irq_restore(flags);
-
-       tty_wakeup(tty);
-}
-
-/*
- * ------------------------------------------------------------
- * mcfrs_throttle()
- * 
- * This routine is called by the upper-layer tty layer to signal that
- * incoming characters should be throttled.
- * ------------------------------------------------------------
- */
-static void mcfrs_throttle(struct tty_struct * tty)
-{
-       struct mcf_serial *info = (struct mcf_serial *)tty->driver_data;
-#ifdef SERIAL_DEBUG_THROTTLE
-       char    buf[64];
-       
-       printk("throttle %s: %d....\n", tty_name(tty, buf),
-              tty->ldisc.chars_in_buffer(tty));
-#endif
-
-       if (serial_paranoia_check(info, tty->name, "mcfrs_throttle"))
-               return;
-       
-       if (I_IXOFF(tty))
-               info->x_char = STOP_CHAR(tty);
-
-       /* Turn off RTS line (do this atomic) */
-}
-
-static void mcfrs_unthrottle(struct tty_struct * tty)
-{
-       struct mcf_serial *info = (struct mcf_serial *)tty->driver_data;
-#ifdef SERIAL_DEBUG_THROTTLE
-       char    buf[64];
-       
-       printk("unthrottle %s: %d....\n", tty_name(tty, buf),
-              tty->ldisc.chars_in_buffer(tty));
-#endif
-
-       if (serial_paranoia_check(info, tty->name, "mcfrs_unthrottle"))
-               return;
-       
-       if (I_IXOFF(tty)) {
-               if (info->x_char)
-                       info->x_char = 0;
-               else
-                       info->x_char = START_CHAR(tty);
-       }
-
-       /* Assert RTS line (do this atomic) */
-}
-
-/*
- * ------------------------------------------------------------
- * mcfrs_ioctl() and friends
- * ------------------------------------------------------------
- */
-
-static int get_serial_info(struct mcf_serial * info,
-                          struct serial_struct * retinfo)
-{
-       struct serial_struct tmp;
-  
-       if (!retinfo)
-               return -EFAULT;
-       memset(&tmp, 0, sizeof(tmp));
-       tmp.type = info->type;
-       tmp.line = info->line;
-       tmp.port = (unsigned int) info->addr;
-       tmp.irq = info->irq;
-       tmp.flags = info->flags;
-       tmp.baud_base = info->baud_base;
-       tmp.close_delay = info->close_delay;
-       tmp.closing_wait = info->closing_wait;
-       tmp.custom_divisor = info->custom_divisor;
-       return copy_to_user(retinfo,&tmp,sizeof(*retinfo)) ? -EFAULT : 0;
-}
-
-static int set_serial_info(struct mcf_serial * info,
-                          struct serial_struct * new_info)
-{
-       struct serial_struct new_serial;
-       struct mcf_serial old_info;
-       int     retval = 0;
-
-       if (!new_info)
-               return -EFAULT;
-       if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
-               return -EFAULT;
-       old_info = *info;
-
-       if (!capable(CAP_SYS_ADMIN)) {
-               if ((new_serial.baud_base != info->baud_base) ||
-                   (new_serial.type != info->type) ||
-                   (new_serial.close_delay != info->close_delay) ||
-                   ((new_serial.flags & ~ASYNC_USR_MASK) !=
-                    (info->flags & ~ASYNC_USR_MASK)))
-                       return -EPERM;
-               info->flags = ((info->flags & ~ASYNC_USR_MASK) |
-                              (new_serial.flags & ASYNC_USR_MASK));
-               info->custom_divisor = new_serial.custom_divisor;
-               goto check_and_exit;
-       }
-
-       if (info->count > 1)
-               return -EBUSY;
-
-       /*
-        * OK, past this point, all the error checking has been done.
-        * At this point, we start making changes.....
-        */
-
-       info->baud_base = new_serial.baud_base;
-       info->flags = ((info->flags & ~ASYNC_FLAGS) |
-                       (new_serial.flags & ASYNC_FLAGS));
-       info->type = new_serial.type;
-       info->close_delay = new_serial.close_delay;
-       info->closing_wait = new_serial.closing_wait;
-
-check_and_exit:
-       retval = startup(info);
-       return retval;
-}
-
-/*
- * get_lsr_info - get line status register info
- *
- * Purpose: Let user call ioctl() to get info when the UART physically
- *         is emptied.  On bus types like RS485, the transmitter must
- *         release the bus after transmitting. This must be done when
- *         the transmit shift register is empty, not be done when the
- *         transmit holding register is empty.  This functionality
- *         allows an RS485 driver to be written in user space. 
- */
-static int get_lsr_info(struct mcf_serial * info, unsigned int *value)
-{
-       volatile unsigned char  *uartp;
-       unsigned long           flags;
-       unsigned char           status;
-
-       local_irq_save(flags);
-       uartp = info->addr;
-       status = (uartp[MCFUART_USR] & MCFUART_USR_TXEMPTY) ? TIOCSER_TEMT : 0;
-       local_irq_restore(flags);
-
-       return put_user(status,value);
-}
-
-/*
- * This routine sends a break character out the serial port.
- */
-static void send_break(        struct mcf_serial * info, int duration)
-{
-       volatile unsigned char  *uartp;
-       unsigned long           flags;
-
-       if (!info->addr)
-               return;
-       set_current_state(TASK_INTERRUPTIBLE);
-       uartp = info->addr;
-
-       local_irq_save(flags);
-       uartp[MCFUART_UCR] = MCFUART_UCR_CMDBREAKSTART;
-       schedule_timeout(duration);
-       uartp[MCFUART_UCR] = MCFUART_UCR_CMDBREAKSTOP;
-       local_irq_restore(flags);
-}
-
-static int mcfrs_tiocmget(struct tty_struct *tty, struct file *file)
-{
-       struct mcf_serial * info = (struct mcf_serial *)tty->driver_data;
-
-       if (serial_paranoia_check(info, tty->name, "mcfrs_ioctl"))
-               return -ENODEV;
-       if (tty->flags & (1 << TTY_IO_ERROR))
-               return -EIO;
-
-       return mcfrs_getsignals(info);
-}
-
-static int mcfrs_tiocmset(struct tty_struct *tty, struct file *file,
-                         unsigned int set, unsigned int clear)
-{
-       struct mcf_serial * info = (struct mcf_serial *)tty->driver_data;
-       int rts = -1, dtr = -1;
-
-       if (serial_paranoia_check(info, tty->name, "mcfrs_ioctl"))
-               return -ENODEV;
-       if (tty->flags & (1 << TTY_IO_ERROR))
-               return -EIO;
-
-       if (set & TIOCM_RTS)
-               rts = 1;
-       if (set & TIOCM_DTR)
-               dtr = 1;
-       if (clear & TIOCM_RTS)
-               rts = 0;
-       if (clear & TIOCM_DTR)
-               dtr = 0;
-
-       mcfrs_setsignals(info, dtr, rts);
-
-       return 0;
-}
-
-static int mcfrs_ioctl(struct tty_struct *tty, struct file * file,
-                   unsigned int cmd, unsigned long arg)
-{
-       struct mcf_serial * info = (struct mcf_serial *)tty->driver_data;
-       int retval, error;
-
-       if (serial_paranoia_check(info, tty->name, "mcfrs_ioctl"))
-               return -ENODEV;
-
-       if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
-           (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD)  &&
-           (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) {
-               if (tty->flags & (1 << TTY_IO_ERROR))
-                   return -EIO;
-       }
-       
-       switch (cmd) {
-               case TCSBRK:    /* SVID version: non-zero arg --> no break */
-                       retval = tty_check_change(tty);
-                       if (retval)
-                               return retval;
-                       tty_wait_until_sent(tty, 0);
-                       if (!arg)
-                               send_break(info, HZ/4); /* 1/4 second */
-                       return 0;
-               case TCSBRKP:   /* support for POSIX tcsendbreak() */
-                       retval = tty_check_change(tty);
-                       if (retval)
-                               return retval;
-                       tty_wait_until_sent(tty, 0);
-                       send_break(info, arg ? arg*(HZ/10) : HZ/4);
-                       return 0;
-               case TIOCGSERIAL:
-                       if (access_ok(VERIFY_WRITE, (void *) arg,
-                                               sizeof(struct serial_struct)))
-                               return get_serial_info(info,
-                                              (struct serial_struct *) arg);
-                       return -EFAULT;
-               case TIOCSSERIAL:
-                       return set_serial_info(info,
-                                              (struct serial_struct *) arg);
-               case TIOCSERGETLSR: /* Get line status register */
-                       if (access_ok(VERIFY_WRITE, (void *) arg,
-                                               sizeof(unsigned int)))
-                               return get_lsr_info(info, (unsigned int *) arg);
-                       return -EFAULT;
-               case TIOCSERGSTRUCT:
-                       error = copy_to_user((struct mcf_serial *) arg,
-                                   info, sizeof(struct mcf_serial));
-                       if (error)
-                               return -EFAULT;
-                       return 0;
-                       
-#ifdef TIOCSET422
-               case TIOCSET422: {
-                       unsigned int val;
-                       get_user(val, (unsigned int *) arg);
-                       mcf_setpa(MCFPP_PA11, (val ? 0 : MCFPP_PA11));
-                       break;
-               }
-               case TIOCGET422: {
-                       unsigned int val;
-                       val = (mcf_getpa() & MCFPP_PA11) ? 0 : 1;
-                       put_user(val, (unsigned int *) arg);
-                       break;
-               }
-#endif
-
-               default:
-                       return -ENOIOCTLCMD;
-               }
-       return 0;
-}
-
-static void mcfrs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
-{
-       struct mcf_serial *info = (struct mcf_serial *)tty->driver_data;
-
-       if (tty->termios->c_cflag == old_termios->c_cflag)
-               return;
-
-       mcfrs_change_speed(info);
-
-       if ((old_termios->c_cflag & CRTSCTS) &&
-           !(tty->termios->c_cflag & CRTSCTS)) {
-               tty->hw_stopped = 0;
-               mcfrs_setsignals(info, -1, 1);
-#if 0
-               mcfrs_start(tty);
-#endif
-       }
-}
-
-/*
- * ------------------------------------------------------------
- * mcfrs_close()
- * 
- * This routine is called when the serial port gets closed.  First, we
- * wait for the last remaining data to be sent.  Then, we unlink its
- * S structure from the interrupt chain if necessary, and we free
- * that IRQ if nothing is left in the chain.
- * ------------------------------------------------------------
- */
-static void mcfrs_close(struct tty_struct *tty, struct file * filp)
-{
-       volatile unsigned char  *uartp;
-       struct mcf_serial       *info = (struct mcf_serial *)tty->driver_data;
-       unsigned long           flags;
-
-       if (!info || serial_paranoia_check(info, tty->name, "mcfrs_close"))
-               return;
-       
-       local_irq_save(flags);
-       
-       if (tty_hung_up_p(filp)) {
-               local_irq_restore(flags);
-               return;
-       }
-       
-#ifdef SERIAL_DEBUG_OPEN
-       printk("mcfrs_close ttyS%d, count = %d\n", info->line, info->count);
-#endif
-       if ((tty->count == 1) && (info->count != 1)) {
-               /*
-                * Uh, oh.  tty->count is 1, which means that the tty
-                * structure will be freed.  Info->count should always
-                * be one in these conditions.  If it's greater than
-                * one, we've got real problems, since it means the
-                * serial port won't be shutdown.
-                */
-               printk("MCFRS: bad serial port count; tty->count is 1, "
-                      "info->count is %d\n", info->count);
-               info->count = 1;
-       }
-       if (--info->count < 0) {
-               printk("MCFRS: bad serial port count for ttyS%d: %d\n",
-                      info->line, info->count);
-               info->count = 0;
-       }
-       if (info->count) {
-               local_irq_restore(flags);
-               return;
-       }
-       info->flags |= ASYNC_CLOSING;
-
-       /*
-        * Now we wait for the transmit buffer to clear; and we notify 
-        * the line discipline to only process XON/XOFF characters.
-        */
-       tty->closing = 1;
-       if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
-               tty_wait_until_sent(tty, info->closing_wait);
-
-       /*
-        * At this point we stop accepting input.  To do this, we
-        * disable the receive line status interrupts, and tell the
-        * interrupt driver to stop checking the data ready bit in the
-        * line status register.
-        */
-       info->imr &= ~MCFUART_UIR_RXREADY;
-       uartp = info->addr;
-       uartp[MCFUART_UIMR] = info->imr;
-
-#if 0
-       /* FIXME: do we need to keep this enabled for console?? */
-       if (mcfrs_console_inited && (mcfrs_console_port == info->line)) {
-               /* Do not disable the UART */ ;
-       } else
-#endif
-       shutdown(info);
-       mcfrs_flush_buffer(tty);
-       tty_ldisc_flush(tty);
-       
-       tty->closing = 0;
-       info->event = 0;
-       info->port.tty = NULL;
-#if 0  
-       if (tty->ldisc.num != ldiscs[N_TTY].num) {
-               if (tty->ldisc.close)
-                       (tty->ldisc.close)(tty);
-               tty->ldisc = ldiscs[N_TTY];
-               tty->termios->c_line = N_TTY;
-               if (tty->ldisc.open)
-                       (tty->ldisc.open)(tty);
-       }
-#endif 
-       if (info->blocked_open) {
-               if (info->close_delay) {
-                       msleep_interruptible(jiffies_to_msecs(info->close_delay));
-               }
-               wake_up_interruptible(&info->open_wait);
-       }
-       info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
-       wake_up_interruptible(&info->close_wait);
-       local_irq_restore(flags);
-}
-
-/*
- * mcfrs_wait_until_sent() --- wait until the transmitter is empty
- */
-static void
-mcfrs_wait_until_sent(struct tty_struct *tty, int timeout)
-{
-#ifdef CONFIG_M5272
-#define        MCF5272_FIFO_SIZE       25              /* fifo size + shift reg */
-
-       struct mcf_serial * info = (struct mcf_serial *)tty->driver_data;
-       volatile unsigned char *uartp;
-       unsigned long orig_jiffies, fifo_time, char_time, fifo_cnt;
-
-       if (serial_paranoia_check(info, tty->name, "mcfrs_wait_until_sent"))
-               return;
-
-       orig_jiffies = jiffies;
-
-       /*
-        * Set the check interval to be 1/5 of the approximate time
-        * to send the entire fifo, and make it at least 1.  The check
-        * interval should also be less than the timeout.
-        *
-        * Note: we have to use pretty tight timings here to satisfy
-        * the NIST-PCTS.
-        */
-       lock_kernel();
-
-       fifo_time = (MCF5272_FIFO_SIZE * HZ * 10) / info->baud;
-       char_time = fifo_time / 5;
-       if (char_time == 0)
-               char_time = 1;
-       if (timeout && timeout < char_time)
-               char_time = timeout;
-
-       /*
-        * Clamp the timeout period at 2 * the time to empty the
-        * fifo.  Just to be safe, set the minimum at .5 seconds.
-        */
-       fifo_time *= 2;
-       if (fifo_time < (HZ/2))
-               fifo_time = HZ/2;
-       if (!timeout || timeout > fifo_time)
-               timeout = fifo_time;
-
-       /*
-        * Account for the number of bytes in the UART
-        * transmitter FIFO plus any byte being shifted out.
-        */
-       uartp = (volatile unsigned char *) info->addr;
-       for (;;) {
-               fifo_cnt = (uartp[MCFUART_UTF] & MCFUART_UTF_TXB);
-               if ((uartp[MCFUART_USR] & (MCFUART_USR_TXREADY|
-                               MCFUART_USR_TXEMPTY)) ==
-                       MCFUART_USR_TXREADY)
-                       fifo_cnt++;
-               if (fifo_cnt == 0)
-                       break;
-               msleep_interruptible(jiffies_to_msecs(char_time));
-               if (signal_pending(current))
-                       break;
-               if (timeout && time_after(jiffies, orig_jiffies + timeout))
-                       break;
-       }
-       unlock_kernel();
-#else
-       /*
-        * For the other coldfire models, assume all data has been sent
-        */
-#endif
-}
-
-/*
- * mcfrs_hangup() --- called by tty_hangup() when a hangup is signaled.
- */
-void mcfrs_hangup(struct tty_struct *tty)
-{
-       struct mcf_serial * info = (struct mcf_serial *)tty->driver_data;
-       
-       if (serial_paranoia_check(info, tty->name, "mcfrs_hangup"))
-               return;
-       
-       mcfrs_flush_buffer(tty);
-       shutdown(info);
-       info->event = 0;
-       info->count = 0;
-       info->flags &= ~ASYNC_NORMAL_ACTIVE;
-       info->port.tty = NULL;
-       wake_up_interruptible(&info->open_wait);
-}
-
-/*
- * ------------------------------------------------------------
- * mcfrs_open() and friends
- * ------------------------------------------------------------
- */
-static int block_til_ready(struct tty_struct *tty, struct file * filp,
-                          struct mcf_serial *info)
-{
-       DECLARE_WAITQUEUE(wait, current);
-       int     retval;
-       int     do_clocal = 0;
-
-       /*
-        * If the device is in the middle of being closed, then block
-        * until it's done, and then try again.
-        */
-       if (info->flags & ASYNC_CLOSING) {
-               interruptible_sleep_on(&info->close_wait);
-#ifdef SERIAL_DO_RESTART
-               if (info->flags & ASYNC_HUP_NOTIFY)
-                       return -EAGAIN;
-               else
-                       return -ERESTARTSYS;
-#else
-               return -EAGAIN;
-#endif
-       }
-       
-       /*
-        * If non-blocking mode is set, or the port is not enabled,
-        * then make the check up front and then exit.
-        */
-       if ((filp->f_flags & O_NONBLOCK) ||
-           (tty->flags & (1 << TTY_IO_ERROR))) {
-               info->flags |= ASYNC_NORMAL_ACTIVE;
-               return 0;
-       }
-
-       if (tty->termios->c_cflag & CLOCAL)
-               do_clocal = 1;
-
-       /*
-        * Block waiting for the carrier detect and the line to become
-        * free (i.e., not in use by the callout).  While we are in
-        * this loop, info->count is dropped by one, so that
-        * mcfrs_close() knows when to free things.  We restore it upon
-        * exit, either normal or abnormal.
-        */
-       retval = 0;
-       add_wait_queue(&info->open_wait, &wait);
-#ifdef SERIAL_DEBUG_OPEN
-       printk("block_til_ready before block: ttyS%d, count = %d\n",
-              info->line, info->count);
-#endif
-       info->count--;
-       info->blocked_open++;
-       while (1) {
-               local_irq_disable();
-               mcfrs_setsignals(info, 1, 1);
-               local_irq_enable();
-               current->state = TASK_INTERRUPTIBLE;
-               if (tty_hung_up_p(filp) ||
-                   !(info->flags & ASYNC_INITIALIZED)) {
-#ifdef SERIAL_DO_RESTART
-                       if (info->flags & ASYNC_HUP_NOTIFY)
-                               retval = -EAGAIN;
-                       else
-                               retval = -ERESTARTSYS;  
-#else
-                       retval = -EAGAIN;
-#endif
-                       break;
-               }
-               if (!(info->flags & ASYNC_CLOSING) &&
-                   (do_clocal || (mcfrs_getsignals(info) & TIOCM_CD)))
-                       break;
-               if (signal_pending(current)) {
-                       retval = -ERESTARTSYS;
-                       break;
-               }
-#ifdef SERIAL_DEBUG_OPEN
-               printk("block_til_ready blocking: ttyS%d, count = %d\n",
-                      info->line, info->count);
-#endif
-               schedule();
-       }
-       current->state = TASK_RUNNING;
-       remove_wait_queue(&info->open_wait, &wait);
-       if (!tty_hung_up_p(filp))
-               info->count++;
-       info->blocked_open--;
-#ifdef SERIAL_DEBUG_OPEN
-       printk("block_til_ready after blocking: ttyS%d, count = %d\n",
-              info->line, info->count);
-#endif
-       if (retval)
-               return retval;
-       info->flags |= ASYNC_NORMAL_ACTIVE;
-       return 0;
-}      
-
-/*
- * This routine is called whenever a serial port is opened. It
- * enables interrupts for a serial port, linking in its structure into
- * the IRQ chain.   It also performs the serial-specific
- * initialization for the tty structure.
- */
-int mcfrs_open(struct tty_struct *tty, struct file * filp)
-{
-       struct mcf_serial       *info;
-       int                     retval, line;
-
-       line = tty->index;
-       if ((line < 0) || (line >= NR_PORTS))
-               return -ENODEV;
-       info = mcfrs_table + line;
-       if (serial_paranoia_check(info, tty->name, "mcfrs_open"))
-               return -ENODEV;
-#ifdef SERIAL_DEBUG_OPEN
-       printk("mcfrs_open %s, count = %d\n", tty->name, info->count);
-#endif
-       info->count++;
-       tty->driver_data = info;
-       info->port.tty = tty;
-
-       /*
-        * Start up serial port
-        */
-       retval = startup(info);
-       if (retval)
-               return retval;
-
-       retval = block_til_ready(tty, filp, info);
-       if (retval) {
-#ifdef SERIAL_DEBUG_OPEN
-               printk("mcfrs_open returning after block_til_ready with %d\n",
-                      retval);
-#endif
-               return retval;
-       }
-
-#ifdef SERIAL_DEBUG_OPEN
-       printk("mcfrs_open %s successful...\n", tty->name);
-#endif
-       return 0;
-}
-
-/*
- *     Based on the line number set up the internal interrupt stuff.
- */
-static void mcfrs_irqinit(struct mcf_serial *info)
-{
-#if defined(CONFIG_M5272)
-       volatile unsigned long  *icrp;
-       volatile unsigned long  *portp;
-       volatile unsigned char  *uartp;
-
-       uartp = info->addr;
-       icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR2);
-
-       switch (info->line) {
-       case 0:
-               *icrp = 0xe0000000;
-               break;
-       case 1:
-               *icrp = 0x0e000000;
-               break;
-       default:
-               printk("MCFRS: don't know how to handle UART %d interrupt?\n",
-                       info->line);
-               return;
-       }
-
-       /* Enable the output lines for the serial ports */
-       portp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_PBCNT);
-       *portp = (*portp & ~0x000000ff) | 0x00000055;
-       portp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_PDCNT);
-       *portp = (*portp & ~0x000003fc) | 0x000002a8;
-#elif defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x)
-       volatile unsigned char *icrp, *uartp;
-       volatile unsigned long *imrp;
-
-       uartp = info->addr;
-
-       icrp = (volatile unsigned char *) (MCF_MBAR + MCFICM_INTC0 +
-               MCFINTC_ICR0 + MCFINT_UART0 + info->line);
-       *icrp = 0x30 + info->line; /* level 6, line based priority */
-
-       imrp = (volatile unsigned long *) (MCF_MBAR + MCFICM_INTC0 +
-               MCFINTC_IMRL);
-       *imrp &= ~((1 << (info->irq - MCFINT_VECBASE)) | 1);
-#if defined(CONFIG_M527x)
-       {
-               /*
-                * External Pin Mask Setting & Enable External Pin for Interface
-                * mrcbis@aliceposta.it
-                */
-               u16 *serpin_enable_mask;
-               serpin_enable_mask = (u16 *) (MCF_IPSBAR + MCF_GPIO_PAR_UART);
-               if (info->line == 0)
-                       *serpin_enable_mask |= UART0_ENABLE_MASK;
-               else if (info->line == 1)
-                       *serpin_enable_mask |= UART1_ENABLE_MASK;
-               else if (info->line == 2)
-                       *serpin_enable_mask |= UART2_ENABLE_MASK;
-       }
-#endif
-#if defined(CONFIG_M528x)
-       /* make sure PUAPAR is set for UART0 and UART1 */
-       if (info->line < 2) {
-               volatile unsigned char *portp = (volatile unsigned char *) (MCF_MBAR + MCF5282_GPIO_PUAPAR);
-               *portp |= (0x03 << (info->line * 2));
-       }
-#endif
-#elif defined(CONFIG_M520x)
-       volatile unsigned char *icrp, *uartp;
-       volatile unsigned long *imrp;
-
-       uartp = info->addr;
-
-       icrp = (volatile unsigned char *) (MCF_MBAR + MCFICM_INTC0 +
-               MCFINTC_ICR0 + MCFINT_UART0 + info->line);
-       *icrp = 0x03;
-
-       imrp = (volatile unsigned long *) (MCF_MBAR + MCFICM_INTC0 +
-               MCFINTC_IMRL);
-       *imrp &= ~((1 << (info->irq - MCFINT_VECBASE)) | 1);
-       if (info->line < 2) {
-               unsigned short *uart_par;
-               uart_par = (unsigned short *)(MCF_IPSBAR + MCF_GPIO_PAR_UART);
-               if (info->line == 0)
-                       *uart_par |=  MCF_GPIO_PAR_UART_PAR_UTXD0
-                                 | MCF_GPIO_PAR_UART_PAR_URXD0;
-               else if (info->line == 1)
-                       *uart_par |=  MCF_GPIO_PAR_UART_PAR_UTXD1
-                                 | MCF_GPIO_PAR_UART_PAR_URXD1;
-               } else if (info->line == 2) {
-                       unsigned char *feci2c_par;
-                       feci2c_par = (unsigned char *)(MCF_IPSBAR +  MCF_GPIO_PAR_FECI2C);
-                       *feci2c_par &= ~0x0F;
-                       *feci2c_par |=  MCF_GPIO_PAR_FECI2C_PAR_SCL_UTXD2
-                                   | MCF_GPIO_PAR_FECI2C_PAR_SDA_URXD2;
-               }
-#elif defined(CONFIG_M532x)
-       volatile unsigned char *uartp;
-       uartp = info->addr;
-       switch (info->line) {
-       case 0:
-               MCF_INTC0_ICR26 = 0x3;
-               MCF_INTC0_CIMR = 26;
-               /* GPIO initialization */
-               MCF_GPIO_PAR_UART |= 0x000F;
-               break;
-       case 1:
-               MCF_INTC0_ICR27 = 0x3;
-               MCF_INTC0_CIMR = 27;
-               /* GPIO initialization */
-               MCF_GPIO_PAR_UART |= 0x0FF0;
-               break;
-       case 2:
-               MCF_INTC0_ICR28 = 0x3;
-               MCF_INTC0_CIMR = 28;
-               /* GPIOs also must be initalized, depends on board */
-               break;
-       }
-#else
-       volatile unsigned char  *icrp, *uartp;
-
-       switch (info->line) {
-       case 0:
-               icrp = (volatile unsigned char *) (MCF_MBAR + MCFSIM_UART1ICR);
-               *icrp = /*MCFSIM_ICR_AUTOVEC |*/ MCFSIM_ICR_LEVEL6 |
-                       MCFSIM_ICR_PRI1;
-               mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART1);
-               break;
-       case 1:
-               icrp = (volatile unsigned char *) (MCF_MBAR + MCFSIM_UART2ICR);
-               *icrp = /*MCFSIM_ICR_AUTOVEC |*/ MCFSIM_ICR_LEVEL6 |
-                       MCFSIM_ICR_PRI2;
-               mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART2);
-               break;
-       default:
-               printk("MCFRS: don't know how to handle UART %d interrupt?\n",
-                       info->line);
-               return;
-       }
-
-       uartp = info->addr;
-       uartp[MCFUART_UIVR] = info->irq;
-#endif
-
-       /* Clear mask, so no surprise interrupts. */
-       uartp[MCFUART_UIMR] = 0;
-
-       if (request_irq(info->irq, mcfrs_interrupt, IRQF_DISABLED,
-           "ColdFire UART", NULL)) {
-               printk("MCFRS: Unable to attach ColdFire UART %d interrupt "
-                       "vector=%d\n", info->line, info->irq);
-       }
-
-       return;
-}
-
-
-char *mcfrs_drivername = "ColdFire internal UART serial driver version 1.00\n";
-
-
-/*
- * Serial stats reporting...
- */
-int mcfrs_readproc(char *page, char **start, off_t off, int count,
-                        int *eof, void *data)
-{
-       struct mcf_serial       *info;
-       char                    str[20];
-       int                     len, sigs, i;
-
-       len = sprintf(page, mcfrs_drivername);
-       for (i = 0; (i < NR_PORTS); i++) {
-               info = &mcfrs_table[i];
-               len += sprintf((page + len), "%d: port:%x irq=%d baud:%d ",
-                       i, (unsigned int) info->addr, info->irq, info->baud);
-               if (info->stats.rx || info->stats.tx)
-                       len += sprintf((page + len), "tx:%d rx:%d ",
-                       info->stats.tx, info->stats.rx);
-               if (info->stats.rxframing)
-                       len += sprintf((page + len), "fe:%d ",
-                       info->stats.rxframing);
-               if (info->stats.rxparity)
-                       len += sprintf((page + len), "pe:%d ",
-                       info->stats.rxparity);
-               if (info->stats.rxbreak)
-                       len += sprintf((page + len), "brk:%d ",
-                       info->stats.rxbreak);
-               if (info->stats.rxoverrun)
-                       len += sprintf((page + len), "oe:%d ",
-                       info->stats.rxoverrun);
-
-               str[0] = str[1] = 0;
-               if ((sigs = mcfrs_getsignals(info))) {
-                       if (sigs & TIOCM_RTS)
-                               strcat(str, "|RTS");
-                       if (sigs & TIOCM_CTS)
-                               strcat(str, "|CTS");
-                       if (sigs & TIOCM_DTR)
-                               strcat(str, "|DTR");
-                       if (sigs & TIOCM_CD)
-                               strcat(str, "|CD");
-               }
-
-               len += sprintf((page + len), "%s\n", &str[1]);
-       }
-
-       return(len);
-}
-
-
-/* Finally, routines used to initialize the serial driver. */
-
-static void show_serial_version(void)
-{
-       printk(mcfrs_drivername);
-}
-
-static const struct tty_operations mcfrs_ops = {
-       .open = mcfrs_open,
-       .close = mcfrs_close,
-       .write = mcfrs_write,
-       .flush_chars = mcfrs_flush_chars,
-       .write_room = mcfrs_write_room,
-       .chars_in_buffer = mcfrs_chars_in_buffer,
-       .flush_buffer = mcfrs_flush_buffer,
-       .ioctl = mcfrs_ioctl,
-       .throttle = mcfrs_throttle,
-       .unthrottle = mcfrs_unthrottle,
-       .set_termios = mcfrs_set_termios,
-       .stop = mcfrs_stop,
-       .start = mcfrs_start,
-       .hangup = mcfrs_hangup,
-       .read_proc = mcfrs_readproc,
-       .wait_until_sent = mcfrs_wait_until_sent,
-       .tiocmget = mcfrs_tiocmget,
-       .tiocmset = mcfrs_tiocmset,
-};
-
-/* mcfrs_init inits the driver */
-static int __init
-mcfrs_init(void)
-{
-       struct mcf_serial       *info;
-       unsigned long           flags;
-       int                     i;
-
-       /* Setup base handler, and timer table. */
-#ifdef MCFPP_DCD0
-       init_timer(&mcfrs_timer_struct);
-       mcfrs_timer_struct.function = mcfrs_timer;
-       mcfrs_timer_struct.data = 0;
-       mcfrs_timer_struct.expires = jiffies + HZ/25;
-       add_timer(&mcfrs_timer_struct);
-       mcfrs_ppstatus = mcf_getppdata() & (MCFPP_DCD0 | MCFPP_DCD1);
-#endif
-       mcfrs_serial_driver = alloc_tty_driver(NR_PORTS);
-       if (!mcfrs_serial_driver)
-               return -ENOMEM;
-
-       show_serial_version();
-
-       /* Initialize the tty_driver structure */
-       mcfrs_serial_driver->owner = THIS_MODULE;
-       mcfrs_serial_driver->name = "ttyS";
-       mcfrs_serial_driver->driver_name = "mcfserial";
-       mcfrs_serial_driver->major = TTY_MAJOR;
-       mcfrs_serial_driver->minor_start = 64;
-       mcfrs_serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
-       mcfrs_serial_driver->subtype = SERIAL_TYPE_NORMAL;
-       mcfrs_serial_driver->init_termios = tty_std_termios;
-
-       mcfrs_serial_driver->init_termios.c_cflag =
-               mcfrs_console_cbaud | CS8 | CREAD | HUPCL | CLOCAL;
-       mcfrs_serial_driver->flags = TTY_DRIVER_REAL_RAW;
-
-       tty_set_operations(mcfrs_serial_driver, &mcfrs_ops);
-
-       if (tty_register_driver(mcfrs_serial_driver)) {
-               printk("MCFRS: Couldn't register serial driver\n");
-               put_tty_driver(mcfrs_serial_driver);
-               return(-EBUSY);
-       }
-
-       local_irq_save(flags);
-
-       /*
-        *      Configure all the attached serial ports.
-        */
-       for (i = 0, info = mcfrs_table; (i < NR_PORTS); i++, info++) {
-               info->magic = SERIAL_MAGIC;
-               info->line = i;
-               info->port.tty = NULL;
-               info->custom_divisor = 16;
-               info->close_delay = 50;
-               info->closing_wait = 3000;
-               info->x_char = 0;
-               info->event = 0;
-               info->count = 0;
-               info->blocked_open = 0;
-               INIT_WORK(&info->tqueue, mcfrs_offintr);
-               INIT_WORK(&info->tqueue_hangup, do_serial_hangup);
-               init_waitqueue_head(&info->open_wait);
-               init_waitqueue_head(&info->close_wait);
-
-               info->imr = 0;
-               mcfrs_setsignals(info, 0, 0);
-               mcfrs_irqinit(info);
-
-               printk("ttyS%d at 0x%04x (irq = %d)", info->line,
-                       (unsigned int) info->addr, info->irq);
-               printk(" is a builtin ColdFire UART\n");
-       }
-
-       local_irq_restore(flags);
-       return 0;
-}
-
-module_init(mcfrs_init);
-
-/****************************************************************************/
-/*                          Serial Console                                  */
-/****************************************************************************/
-
-/*
- *     Quick and dirty UART initialization, for console output.
- */
-
-void mcfrs_init_console(void)
-{
-       volatile unsigned char  *uartp;
-       unsigned int            clk;
-
-       /*
-        *      Reset UART, get it into known state...
-        */
-       uartp = (volatile unsigned char *) (MCF_MBAR +
-               (mcfrs_console_port ? MCFUART_BASE2 : MCFUART_BASE1));
-
-       uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETRX;  /* reset RX */
-       uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETTX;  /* reset TX */
-       uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETMRPTR;  /* reset MR pointer */
-
-       /*
-        * Set port for defined baud , 8 data bits, 1 stop bit, no parity.
-        */
-       uartp[MCFUART_UMR] = MCFUART_MR1_PARITYNONE | MCFUART_MR1_CS8;
-       uartp[MCFUART_UMR] = MCFUART_MR2_STOP1;
-
-#ifdef CONFIG_M5272
-{
-       /*
-        * For the MCF5272, also compute the baudrate fraction.
-        */
-       int fraction = MCF_BUSCLK - (clk * 32 * mcfrs_console_baud);
-       fraction *= 16;
-       fraction /= (32 * mcfrs_console_baud);
-       uartp[MCFUART_UFPD] = (fraction & 0xf);         /* set fraction */
-       clk = (MCF_BUSCLK / mcfrs_console_baud) / 32;
-}
-#else
-       clk = ((MCF_BUSCLK / mcfrs_console_baud) + 16) / 32; /* set baud */
-#endif
-
-       uartp[MCFUART_UBG1] = (clk & 0xff00) >> 8;  /* set msb baud */
-       uartp[MCFUART_UBG2] = (clk & 0xff);  /* set lsb baud */
-       uartp[MCFUART_UCSR] = MCFUART_UCSR_RXCLKTIMER | MCFUART_UCSR_TXCLKTIMER;
-       uartp[MCFUART_UCR] = MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE;
-
-       mcfrs_console_inited++;
-       return;
-}
-
-
-/*
- *     Setup for console. Argument comes from the boot command line.
- */
-
-int mcfrs_console_setup(struct console *cp, char *arg)
-{
-       int             i, n = CONSOLE_BAUD_RATE;
-
-       if (!cp)
-               return(-1);
-
-       if (!strncmp(cp->name, "ttyS", 4))
-               mcfrs_console_port = cp->index;
-       else if (!strncmp(cp->name, "cua", 3))
-               mcfrs_console_port = cp->index;
-       else
-               return(-1);
-
-       if (arg)
-               n = simple_strtoul(arg,NULL,0);
-       for (i = 0; i < MCFRS_BAUD_TABLE_SIZE; i++)
-               if (mcfrs_baud_table[i] == n)
-                       break;
-       if (i < MCFRS_BAUD_TABLE_SIZE) {
-               mcfrs_console_baud = n;
-               mcfrs_console_cbaud = 0;
-               if (i > 15) {
-                       mcfrs_console_cbaud |= CBAUDEX;
-                       i -= 15;
-               }
-               mcfrs_console_cbaud |= i;
-       }
-       mcfrs_init_console(); /* make sure baud rate changes */
-       return(0);
-}
-
-
-static struct tty_driver *mcfrs_console_device(struct console *c, int *index)
-{
-       *index = c->index;
-       return mcfrs_serial_driver;
-}
-
-
-/*
- *     Output a single character, using UART polled mode.
- *     This is used for console output.
- */
-
-int mcfrs_put_char(char ch)
-{
-       volatile unsigned char  *uartp;
-       unsigned long           flags;
-       int                     i;
-
-       uartp = (volatile unsigned char *) (MCF_MBAR +
-               (mcfrs_console_port ? MCFUART_BASE2 : MCFUART_BASE1));
-
-       local_irq_save(flags);
-       for (i = 0; (i < 0x10000); i++) {
-               if (uartp[MCFUART_USR] & MCFUART_USR_TXREADY)
-                       break;
-       }
-       if (i < 0x10000) {
-               uartp[MCFUART_UTB] = ch;
-               for (i = 0; (i < 0x10000); i++)
-                       if (uartp[MCFUART_USR] & MCFUART_USR_TXEMPTY)
-                               break;
-       }
-       if (i >= 0x10000)
-               mcfrs_init_console(); /* try and get it back */
-       local_irq_restore(flags);
-
-       return 1;
-}
-
-
-/*
- * rs_console_write is registered for printk output.
- */
-
-void mcfrs_console_write(struct console *cp, const char *p, unsigned len)
-{
-       if (!mcfrs_console_inited)
-               mcfrs_init_console();
-       while (len-- > 0) {
-               if (*p == '\n')
-                       mcfrs_put_char('\r');
-               mcfrs_put_char(*p++);
-       }
-}
-
-/*
- * declare our consoles
- */
-
-struct console mcfrs_console = {
-       .name           = "ttyS",
-       .write          = mcfrs_console_write,
-       .device         = mcfrs_console_device,
-       .setup          = mcfrs_console_setup,
-       .flags          = CON_PRINTBUFFER,
-       .index          = -1,
-};
-
-static int __init mcfrs_console_init(void)
-{
-       register_console(&mcfrs_console);
-       return 0;
-}
-
-console_initcall(mcfrs_console_init);
-
-/****************************************************************************/
diff --git a/drivers/serial/mcfserial.h b/drivers/serial/mcfserial.h
deleted file mode 100644 (file)
index 56420e2..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * mcfserial.c -- serial driver for ColdFire internal UARTS.
- *
- * Copyright (c) 1999 Greg Ungerer <gerg@snapgear.com>
- * Copyright (c) 2000-2001 Lineo, Inc. <www.lineo.com>
- * Copyright (c) 2002 SnapGear Inc., <www.snapgear.com>
- *
- * Based on code from 68332serial.c which was:
- *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1998 TSHG
- * Copyright (c) 1999 Rt-Control Inc. <jeff@uclinux.org>
- */ 
-#ifndef _MCF_SERIAL_H
-#define _MCF_SERIAL_H
-
-#include <linux/serial.h>
-
-#ifdef __KERNEL__
-
-/*
- *     Define a local serial stats structure.
- */
-
-struct mcf_stats {
-       unsigned int    rx;
-       unsigned int    tx;
-       unsigned int    rxbreak;
-       unsigned int    rxframing;
-       unsigned int    rxparity;
-       unsigned int    rxoverrun;
-};
-
-
-/*
- * This is our internal structure for each serial port's state.
- * Each serial port has one of these structures associated with it.
- */
-
-struct mcf_serial {
-       int                     magic;
-       volatile unsigned char  *addr;          /* UART memory address */
-       int                     irq;
-       int                     flags;          /* defined in tty.h */
-       int                     type;           /* UART type */
-       struct tty_struct       *tty;
-       unsigned char           imr;            /* Software imr register */
-       unsigned int            baud;
-       int                     sigs;
-       int                     custom_divisor;
-       int                     x_char; /* xon/xoff character */
-       int                     baud_base;
-       int                     close_delay;
-       unsigned short          closing_wait;
-       unsigned short          closing_wait2;
-       unsigned long           event;
-       int                     line;
-       int                     count;      /* # of fd on device */
-       int                     blocked_open; /* # of blocked opens */
-       unsigned char           *xmit_buf;
-       int                     xmit_head;
-       int                     xmit_tail;
-       int                     xmit_cnt;
-       struct mcf_stats        stats;
-       struct work_struct      tqueue;
-       struct work_struct      tqueue_hangup;
-       wait_queue_head_t       open_wait;
-       wait_queue_head_t       close_wait;
-
-};
-
-#endif /* __KERNEL__ */
-
-#endif /* _MCF_SERIAL_H */
index f977c98cfa956749cb3bd37211d30bb6115d2190..6bdf3362e3b1e5f743ae8bad1f0bc8c9f682bf08 100644 (file)
@@ -2051,7 +2051,8 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *port)
                                        "transmitter\n",
                               port->dev ? port->dev->bus_id : "",
                               port->dev ? ": " : "",
-                              drv->dev_name, port->line);
+                              drv->dev_name,
+                              drv->tty_driver->name_base + port->line);
 
                ops->shutdown(port);
        }
@@ -2154,12 +2155,11 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port)
 
        switch (port->iotype) {
        case UPIO_PORT:
-               snprintf(address, sizeof(address),
-                        "I/O 0x%x", port->iobase);
+               snprintf(address, sizeof(address), "I/O 0x%lx", port->iobase);
                break;
        case UPIO_HUB6:
                snprintf(address, sizeof(address),
-                        "I/O 0x%x offset 0x%x", port->iobase, port->hub6);
+                        "I/O 0x%lx offset 0x%x", port->iobase, port->hub6);
                break;
        case UPIO_MEM:
        case UPIO_MEM32:
@@ -2177,7 +2177,9 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port)
        printk(KERN_INFO "%s%s%s%d at %s (irq = %d) is a %s\n",
               port->dev ? port->dev->bus_id : "",
               port->dev ? ": " : "",
-              drv->dev_name, port->line, address, port->irq, uart_type(port));
+              drv->dev_name,
+              drv->tty_driver->name_base + port->line,
+              address, port->irq, uart_type(port));
 }
 
 static void
index 79ea98c66fa8d8c1f91ef2b045e9fc19d52375de..99fb7dc59c4540911b01a2cd72662dbcd54cf113 100644 (file)
@@ -272,7 +272,7 @@ static void aircable_read(struct work_struct *work)
         * 64 bytes, to ensure I do not get throttled.
         * Ask USB mailing list for better aproach.
         */
-       tty = port->port.tty;
+       tty = tty_port_tty_get(&port->port);
 
        if (!tty) {
                schedule_work(&priv->rx_work);
@@ -283,12 +283,13 @@ static void aircable_read(struct work_struct *work)
        count = min(64, serial_buf_data_avail(priv->rx_buf));
 
        if (count <= 0)
-               return; /* We have finished sending everything. */
+               goto out; /* We have finished sending everything. */
 
        tty_prepare_flip_string(tty, &data, count);
        if (!data) {
-               err("%s- kzalloc(%d) failed.", __func__, count);
-               return;
+               dev_err(&port->dev, "%s- kzalloc(%d) failed.",
+                                                       __func__, count);
+               goto out;
        }
 
        serial_buf_get(priv->rx_buf, data, count);
@@ -297,7 +298,8 @@ static void aircable_read(struct work_struct *work)
 
        if (serial_buf_data_avail(priv->rx_buf))
                schedule_work(&priv->rx_work);
-
+out:           
+       tty_kref_put(tty);
        return;
 }
 /* End of private methods */
@@ -495,7 +497,7 @@ static void aircable_read_bulk_callback(struct urb *urb)
        usb_serial_debug_data(debug, &port->dev, __func__,
                                urb->actual_length, urb->transfer_buffer);
 
-       tty = port->port.tty;
+       tty = tty_port_tty_get(&port->port);
        if (tty && urb->actual_length) {
                if (urb->actual_length <= 2) {
                        /* This is an incomplete package */
@@ -527,6 +529,7 @@ static void aircable_read_bulk_callback(struct urb *urb)
                }
                aircable_read(&priv->rx_work);
        }
+       tty_kref_put(tty);
 
        /* Schedule the next read _if_ we are still open */
        if (port->port.count) {
index 2ebe06c3405a219d7d6a7200f0956baf2c466555..1913bc7c5f0b6c6d38b17f1ab709435e1f6d6417 100644 (file)
@@ -322,7 +322,7 @@ static void belkin_sa_read_int_callback(struct urb *urb)
         * to look in to this before committing any code.
         */
        if (priv->last_lsr & BELKIN_SA_LSR_ERR) {
-               tty = port->port.tty;
+               tty = tty_port_tty_get(&port->port);
                /* Overrun Error */
                if (priv->last_lsr & BELKIN_SA_LSR_OE) {
                }
@@ -335,6 +335,7 @@ static void belkin_sa_read_int_callback(struct urb *urb)
                /* Break Indicator */
                if (priv->last_lsr & BELKIN_SA_LSR_BI) {
                }
+               tty_kref_put(tty);
        }
 #endif
        spin_unlock_irqrestore(&priv->lock, flags);
index e980766bb84bed3fc05abb203dc3c3bc02b7daff..5b20de130e08399045e3134dff18bfb8543af5f4 100644 (file)
@@ -117,7 +117,7 @@ static int usb_console_setup(struct console *co, char *options)
        }
 
        port = serial->port[0];
-       port->port.tty = NULL;
+       tty_port_tty_set(&port->port, NULL);
 
        info->port = port;
 
@@ -143,7 +143,7 @@ static int usb_console_setup(struct console *co, char *options)
                        }
                        memset(&dummy, 0, sizeof(struct ktermios));
                        tty->termios = termios;
-                       port->port.tty = tty;
+                       tty_port_tty_set(&port->port, tty);
                }
 
                /* only call the device specific open if this
@@ -163,7 +163,7 @@ static int usb_console_setup(struct console *co, char *options)
                        tty_termios_encode_baud_rate(termios, baud, baud);
                        serial->type->set_termios(tty, port, &dummy);
 
-                       port->port.tty = NULL;
+                       tty_port_tty_set(&port->port, NULL);
                        kfree(termios);
                        kfree(tty);
                }
@@ -176,7 +176,7 @@ out:
        return retval;
 free_termios:
        kfree(termios);
-       port->port.tty = NULL;
+       tty_port_tty_set(&port->port, NULL);
 free_tty:
        kfree(tty);
 reset_open_count:
index b4d72351cb9697964fafc3ac8f2f1a4bf90cc15b..94ef36c4764bcc3378e839055299b8356848c8df 100644 (file)
@@ -384,7 +384,7 @@ static void cyberjack_read_bulk_callback(struct urb *urb)
                return;
        }
 
-       tty = port->port.tty;
+       tty = tty_port_tty_get(&port->port);
        if (!tty) {
                dbg("%s - ignoring since device not open\n", __func__);
                return;
@@ -394,6 +394,7 @@ static void cyberjack_read_bulk_callback(struct urb *urb)
                tty_insert_flip_string(tty, data, urb->actual_length);
                tty_flip_buffer_push(tty);
        }
+       tty_kref_put(tty);
 
        spin_lock(&priv->lock);
 
index 22837a3f2f899e963f0d944814d222bcd2e494f5..f3514a91f9154836366e7de1804d94a163d795a8 100644 (file)
@@ -1286,7 +1286,7 @@ static void cypress_read_int_callback(struct urb *urb)
        }
        spin_unlock_irqrestore(&priv->lock, flags);
 
-       tty = port->port.tty;
+       tty = tty_port_tty_get(&port->port);
        if (!tty) {
                dbg("%s - bad tty pointer - exiting", __func__);
                return;
@@ -1362,7 +1362,7 @@ static void cypress_read_int_callback(struct urb *urb)
                                        data[i]);
                        tty_insert_flip_char(tty, data[i], tty_flag);
                }
-               tty_flip_buffer_push(port->port.tty);
+               tty_flip_buffer_push(tty);
        }
 
        spin_lock_irqsave(&priv->lock, flags);
@@ -1371,6 +1371,7 @@ static void cypress_read_int_callback(struct urb *urb)
        spin_unlock_irqrestore(&priv->lock, flags);
 
 continue_read:
+       tty_kref_put(tty);
 
        /* Continue trying to always read... unless the port has closed. */
 
index 240aad1acaab80f8a802b6b67cd4f3ffed911a9d..5756ac6d6c923ccf30a4ba66f2c036599bf203cd 100644 (file)
@@ -604,7 +604,9 @@ static void digi_wakeup_write_lock(struct work_struct *work)
 
 static void digi_wakeup_write(struct usb_serial_port *port)
 {
-       tty_wakeup(port->port.tty);
+       struct tty_struct *tty = tty_port_tty_get(&port->port);
+       tty_wakeup(tty);
+       tty_kref_put(tty);
 }
 
 
@@ -1668,7 +1670,7 @@ static int digi_read_inb_callback(struct urb *urb)
 {
 
        struct usb_serial_port *port = urb->context;
-       struct tty_struct *tty = port->port.tty;
+       struct tty_struct *tty;
        struct digi_port *priv = usb_get_serial_port_data(port);
        int opcode = ((unsigned char *)urb->transfer_buffer)[0];
        int len = ((unsigned char *)urb->transfer_buffer)[1];
@@ -1692,6 +1694,7 @@ static int digi_read_inb_callback(struct urb *urb)
                return -1;
        }
 
+       tty = tty_port_tty_get(&port->port);
        spin_lock(&priv->dp_port_lock);
 
        /* check for throttle; if set, do not resubmit read urb */
@@ -1735,6 +1738,7 @@ static int digi_read_inb_callback(struct urb *urb)
                }
        }
        spin_unlock(&priv->dp_port_lock);
+       tty_kref_put(tty);
 
        if (opcode == DIGI_CMD_RECEIVE_DISABLE)
                dbg("%s: got RECEIVE_DISABLE", __func__);
@@ -1760,6 +1764,7 @@ static int digi_read_oob_callback(struct urb *urb)
 
        struct usb_serial_port *port = urb->context;
        struct usb_serial *serial = port->serial;
+       struct tty_struct *tty;
        struct digi_port *priv = usb_get_serial_port_data(port);
        int opcode, line, status, val;
        int i;
@@ -1787,10 +1792,11 @@ static int digi_read_oob_callback(struct urb *urb)
                if (priv == NULL)
                        return -1;
 
+               tty = tty_port_tty_get(&port->port);
                rts = 0;
                if (port->port.count)
-                       rts = port->port.tty->termios->c_cflag & CRTSCTS;
-
+                       rts = tty->termios->c_cflag & CRTSCTS;
+               
                if (opcode == DIGI_CMD_READ_INPUT_SIGNALS) {
                        spin_lock(&priv->dp_port_lock);
                        /* convert from digi flags to termiox flags */
@@ -1798,14 +1804,14 @@ static int digi_read_oob_callback(struct urb *urb)
                                priv->dp_modem_signals |= TIOCM_CTS;
                                /* port must be open to use tty struct */
                                if (rts) {
-                                       port->port.tty->hw_stopped = 0;
+                                       tty->hw_stopped = 0;
                                        digi_wakeup_write(port);
                                }
                        } else {
                                priv->dp_modem_signals &= ~TIOCM_CTS;
                                /* port must be open to use tty struct */
                                if (rts)
-                                       port->port.tty->hw_stopped = 1;
+                                       tty->hw_stopped = 1;
                        }
                        if (val & DIGI_READ_INPUT_SIGNALS_DSR)
                                priv->dp_modem_signals |= TIOCM_DSR;
@@ -1830,6 +1836,7 @@ static int digi_read_oob_callback(struct urb *urb)
                } else if (opcode == DIGI_CMD_IFLUSH_FIFO) {
                        wake_up_interruptible(&priv->dp_flush_wait);
                }
+               tty_kref_put(tty);
        }
        return 0;
 
index a6ab5b58d9ca5c6456a9a56eb7606e4fb18c4b0e..1072e847280fd88df4a5fc1f9770d5a36a051692 100644 (file)
@@ -33,9 +33,8 @@
  *     Moved MOD_DEC_USE_COUNT to end of empeg_close().
  *
  * (12/03/2000) gb
- *     Added port->port.tty->ldisc.set_termios(port->port.tty, NULL) to
- *     empeg_open(). This notifies the tty driver that the termios have
- *     changed.
+ *     Added tty->ldisc.set_termios(port, tty, NULL) to empeg_open().
+ *     This notifies the tty driver that the termios have changed.
  *
  * (11/13/2000) gb
  *     Moved tty->low_latency = 1 from empeg_read_bulk_callback() to
@@ -354,7 +353,7 @@ static void empeg_read_bulk_callback(struct urb *urb)
 
        usb_serial_debug_data(debug, &port->dev, __func__,
                                                urb->actual_length, data);
-       tty = port->port.tty;
+       tty = tty_port_tty_get(&port->port);
 
        if (urb->actual_length) {
                tty_buffer_request_room(tty, urb->actual_length);
@@ -362,6 +361,7 @@ static void empeg_read_bulk_callback(struct urb *urb)
                tty_flip_buffer_push(tty);
                bytes_in += urb->actual_length;
        }
+       tty_kref_put(tty);
 
        /* Continue trying to always read  */
        usb_fill_bulk_urb(
index 3dc93b542b30634cd23bbbe012b16034c84f6449..c2ac129557aae7dd599ccfbca2a3ddfcebd8aeb5 100644 (file)
@@ -860,7 +860,7 @@ static int update_mctrl(struct usb_serial_port *port, unsigned int set,
 
        kfree(buf);
        if (rv < 0) {
-               err("%s Error from MODEM_CTRL urb: DTR %s, RTS %s",
+               dbg("%s Error from MODEM_CTRL urb: DTR %s, RTS %s",
                                __func__,
                                (set & TIOCM_DTR) ? "HIGH" :
                                (clear & TIOCM_DTR) ? "LOW" : "unchanged",
@@ -1808,7 +1808,7 @@ static void ftdi_read_bulk_callback(struct urb *urb)
        if (port->port.count <= 0)
                return;
 
-       tty = port->port.tty;
+       tty = tty_port_tty_get(&port->port);
        if (!tty) {
                dbg("%s - bad tty pointer - exiting", __func__);
                return;
@@ -1817,7 +1817,7 @@ static void ftdi_read_bulk_callback(struct urb *urb)
        priv = usb_get_serial_port_data(port);
        if (!priv) {
                dbg("%s - bad port private data pointer - exiting", __func__);
-               return;
+               goto out;
        }
 
        if (urb != port->read_urb)
@@ -1827,7 +1827,7 @@ static void ftdi_read_bulk_callback(struct urb *urb)
                /* This will happen at close every time so it is a dbg not an
                   err */
                dbg("(this is ok on close) nonzero read bulk status received: %d", status);
-               return;
+               goto out;
        }
 
        /* count data bytes, but not status bytes */
@@ -1838,7 +1838,8 @@ static void ftdi_read_bulk_callback(struct urb *urb)
        spin_unlock_irqrestore(&priv->rx_lock, flags);
 
        ftdi_process_read(&priv->rx_work.work);
-
+out:
+       tty_kref_put(tty);
 } /* ftdi_read_bulk_callback */
 
 
@@ -1863,7 +1864,7 @@ static void ftdi_process_read(struct work_struct *work)
        if (port->port.count <= 0)
                return;
 
-       tty = port->port.tty;
+       tty = tty_port_tty_get(&port->port);
        if (!tty) {
                dbg("%s - bad tty pointer - exiting", __func__);
                return;
@@ -1872,13 +1873,13 @@ static void ftdi_process_read(struct work_struct *work)
        priv = usb_get_serial_port_data(port);
        if (!priv) {
                dbg("%s - bad port private data pointer - exiting", __func__);
-               return;
+               goto out;
        }
 
        urb = port->read_urb;
        if (!urb) {
                dbg("%s - bad read_urb pointer - exiting", __func__);
-               return;
+               goto out;
        }
 
        data = urb->transfer_buffer;
@@ -2020,7 +2021,7 @@ static void ftdi_process_read(struct work_struct *work)
                        schedule_delayed_work(&priv->rx_work, 1);
                else
                        dbg("%s - port is closed", __func__);
-               return;
+               goto out;
        }
 
        /* urb is completely processed */
@@ -2041,6 +2042,8 @@ static void ftdi_process_read(struct work_struct *work)
                        err("%s - failed resubmitting read urb, error %d",
                                                        __func__, result);
        }
+out:
+       tty_kref_put(tty);
 } /* ftdi_process_read */
 
 
@@ -2256,7 +2259,7 @@ static int ftdi_tiocmget(struct tty_struct *tty, struct file *file)
                           0, 0,
                           buf, 1, WDR_TIMEOUT);
                if (ret < 0) {
-                       err("%s Could not get modem status of device - err: %d", __func__,
+                       dbg("%s Could not get modem status of device - err: %d", __func__,
                            ret);
                        return ret;
                }
@@ -2275,7 +2278,7 @@ static int ftdi_tiocmget(struct tty_struct *tty, struct file *file)
                                   0, priv->interface,
                                   buf, 2, WDR_TIMEOUT);
                if (ret < 0) {
-                       err("%s Could not get modem status of device - err: %d", __func__,
+                       dbg("%s Could not get modem status of device - err: %d", __func__,
                            ret);
                        return ret;
                }
index d95382088075923ab47ae4fc869784e03c0520d4..2ad0569bcf19ec7ceeee03ccf3ac3f3af55d1cca 100644 (file)
@@ -276,7 +276,7 @@ static inline int isAbortTrfCmnd(const unsigned char *buf)
 static void send_to_tty(struct usb_serial_port *port,
                        char *data, unsigned int actual_length)
 {
-       struct tty_struct *tty = port->port.tty;
+       struct tty_struct *tty = tty_port_tty_get(&port->port);
 
        if (tty && actual_length) {
 
@@ -287,6 +287,7 @@ static void send_to_tty(struct usb_serial_port *port,
                tty_insert_flip_string(tty, data, actual_length);
                tty_flip_buffer_push(tty);
        }
+       tty_kref_put(tty);
 }
 
 
index fe84c88ec20cae94b9d1990b1e48be0ef87cb364..814909f1ee630b34092e7e22fa6f764e0a1d9e3a 100644 (file)
@@ -330,7 +330,7 @@ static void resubmit_read_urb(struct usb_serial_port *port, gfp_t mem_flags)
 static void flush_and_resubmit_read_urb(struct usb_serial_port *port)
 {
        struct urb *urb = port->read_urb;
-       struct tty_struct *tty = port->port.tty;
+       struct tty_struct *tty = tty_port_tty_get(&port->port);
        int room;
 
        /* Push data to tty */
@@ -341,6 +341,7 @@ static void flush_and_resubmit_read_urb(struct usb_serial_port *port)
                        tty_flip_buffer_push(tty);
                }
        }
+       tty_kref_put(tty);
 
        resubmit_read_urb(port, GFP_ATOMIC);
 }
index bfa508ddb0fed3f97062bf66e16326b765dbcbe1..611f97fd62f1b0eb2799cb58941fa8c0d5921e50 100644 (file)
@@ -600,6 +600,7 @@ static void edge_interrupt_callback(struct urb *urb)
        struct edgeport_serial  *edge_serial = urb->context;
        struct edgeport_port *edge_port;
        struct usb_serial_port *port;
+       struct tty_struct *tty;
        unsigned char *data = urb->transfer_buffer;
        int length = urb->actual_length;
        int bytes_avail;
@@ -675,9 +676,12 @@ static void edge_interrupt_callback(struct urb *urb)
 
                                        /* tell the tty driver that something
                                           has changed */
-                                       if (edge_port->port->port.tty)
-                                               tty_wakeup(edge_port->port->port.tty);
-
+                                       tty = tty_port_tty_get(
+                                               &edge_port->port->port);
+                                       if (tty) {
+                                               tty_wakeup(tty);
+                                               tty_kref_put(tty);
+                                       }
                                        /* Since we have more credit, check
                                           if more data can be sent */
                                        send_more_port_data(edge_serial,
@@ -778,13 +782,14 @@ static void edge_bulk_out_data_callback(struct urb *urb)
                    __func__, status);
        }
 
-       tty = edge_port->port->port.tty;
+       tty = tty_port_tty_get(&edge_port->port->port);
 
        if (tty && edge_port->open) {
                /* let the tty driver wakeup if it has a special
                   write_wakeup function */
                tty_wakeup(tty);
        }
+       tty_kref_put(tty);
 
        /* Release the Write URB */
        edge_port->write_in_progress = false;
@@ -826,11 +831,12 @@ static void edge_bulk_out_cmd_callback(struct urb *urb)
        }
 
        /* Get pointer to tty */
-       tty = edge_port->port->port.tty;
+       tty = tty_port_tty_get(&edge_port->port->port);
 
        /* tell the tty driver that something has changed */
        if (tty && edge_port->open)
                tty_wakeup(tty);
+       tty_kref_put(tty);
 
        /* we have completed the command */
        edge_port->commandPending = false;
@@ -1932,11 +1938,13 @@ static void process_rcvd_data(struct edgeport_serial *edge_serial,
                                                        edge_serial->rxPort];
                                edge_port = usb_get_serial_port_data(port);
                                if (edge_port->open) {
-                                       tty = edge_port->port->port.tty;
+                                       tty = tty_port_tty_get(
+                                               &edge_port->port->port);
                                        if (tty) {
                                                dbg("%s - Sending %d bytes to TTY for port %d",
                                                        __func__, rxLen, edge_serial->rxPort);
                                                edge_tty_recv(&edge_serial->serial->dev->dev, tty, buffer, rxLen);
+                                               tty_kref_put(tty);
                                        }
                                        edge_port->icount.rx += rxLen;
                                }
@@ -1971,6 +1979,7 @@ static void process_rcvd_status(struct edgeport_serial *edge_serial,
 {
        struct usb_serial_port *port;
        struct edgeport_port *edge_port;
+       struct tty_struct *tty;
        __u8 code = edge_serial->rxStatusCode;
 
        /* switch the port pointer to the one being currently talked about */
@@ -2020,10 +2029,12 @@ static void process_rcvd_status(struct edgeport_serial *edge_serial,
 
                /* send the current line settings to the port so we are
                   in sync with any further termios calls */
-               /* FIXME: locking on tty */
-               if (edge_port->port->port.tty)
-                       change_port_settings(edge_port->port->port.tty,
-                               edge_port, edge_port->port->port.tty->termios);
+               tty = tty_port_tty_get(&edge_port->port->port);
+               if (tty) {
+                       change_port_settings(tty,
+                               edge_port, tty->termios);
+                       tty_kref_put(tty);
+               }
 
                /* we have completed the open */
                edge_port->openPending = false;
@@ -2163,10 +2174,14 @@ static void handle_new_lsr(struct edgeport_port *edge_port, __u8 lsrData,
        }
 
        /* Place LSR data byte into Rx buffer */
-       if (lsrData && edge_port->port->port.tty)
-               edge_tty_recv(&edge_port->port->dev,
-                                       edge_port->port->port.tty, &data, 1);
-
+       if (lsrData) {
+               struct tty_struct *tty =
+                               tty_port_tty_get(&edge_port->port->port);
+               if (tty) {
+                       edge_tty_recv(&edge_port->port->dev, tty, &data, 1);
+                       tty_kref_put(tty);
+               }
+       }
        /* update input line counters */
        icount = &edge_port->icount;
        if (newLsr & LSR_BREAK)
index cb4c54316cf56a935691ceba62971c3fcd5963c9..541dd8e6e7a2a232ea826587efdfab136c75f82b 100644 (file)
@@ -572,7 +572,7 @@ static void chase_port(struct edgeport_port *port, unsigned long timeout,
                                                                int flush)
 {
        int baud_rate;
-       struct tty_struct *tty = port->port->port.tty;
+       struct tty_struct *tty = tty_port_tty_get(&port->port->port);
        wait_queue_t wait;
        unsigned long flags;
 
@@ -599,6 +599,7 @@ static void chase_port(struct edgeport_port *port, unsigned long timeout,
        if (flush)
                edge_buf_clear(port->ep_out_buf);
        spin_unlock_irqrestore(&port->ep_lock, flags);
+       tty_kref_put(tty);
 
        /* wait for data to drain from the device */
        timeout += jiffies;
@@ -1554,7 +1555,7 @@ static void handle_new_msr(struct edgeport_port *edge_port, __u8 msr)
        /* Save the new modem status */
        edge_port->shadow_msr = msr & 0xf0;
 
-       tty = edge_port->port->port.tty;
+       tty = tty_port_tty_get(&edge_port->port->port);
        /* handle CTS flow control */
        if (tty && C_CRTSCTS(tty)) {
                if (msr & EDGEPORT_MSR_CTS) {
@@ -1564,6 +1565,7 @@ static void handle_new_msr(struct edgeport_port *edge_port, __u8 msr)
                        tty->hw_stopped = 1;
                }
        }
+       tty_kref_put(tty);
 
        return;
 }
@@ -1574,6 +1576,7 @@ static void handle_new_lsr(struct edgeport_port *edge_port, int lsr_data,
        struct async_icount *icount;
        __u8 new_lsr = (__u8)(lsr & (__u8)(LSR_OVER_ERR | LSR_PAR_ERR |
                                                LSR_FRM_ERR | LSR_BREAK));
+       struct tty_struct *tty;
 
        dbg("%s - %02x", __func__, new_lsr);
 
@@ -1587,8 +1590,13 @@ static void handle_new_lsr(struct edgeport_port *edge_port, int lsr_data,
                new_lsr &= (__u8)(LSR_OVER_ERR | LSR_BREAK);
 
        /* Place LSR data byte into Rx buffer */
-       if (lsr_data && edge_port->port->port.tty)
-               edge_tty_recv(&edge_port->port->dev, edge_port->port->port.tty, &data, 1);
+       if (lsr_data) {
+               tty = tty_port_tty_get(&edge_port->port->port);
+               if (tty) {
+                       edge_tty_recv(&edge_port->port->dev, tty, &data, 1);
+                       tty_kref_put(tty);
+               }
+       }
 
        /* update input line counters */
        icount = &edge_port->icount;
@@ -1749,7 +1757,7 @@ static void edge_bulk_in_callback(struct urb *urb)
                ++data;
        }
 
-       tty = edge_port->port->port.tty;
+       tty = tty_port_tty_get(&edge_port->port->port);
        if (tty && urb->actual_length) {
                usb_serial_debug_data(debug, &edge_port->port->dev,
                                        __func__, urb->actual_length, data);
@@ -1761,6 +1769,7 @@ static void edge_bulk_in_callback(struct urb *urb)
                                                        urb->actual_length);
                edge_port->icount.rx += urb->actual_length;
        }
+       tty_kref_put(tty);
 
 exit:
        /* continue read unless stopped */
@@ -1796,6 +1805,7 @@ static void edge_bulk_out_callback(struct urb *urb)
        struct usb_serial_port *port = urb->context;
        struct edgeport_port *edge_port = usb_get_serial_port_data(port);
        int status = urb->status;
+       struct tty_struct *tty;
 
        dbg("%s - port %d", __func__, port->number);
 
@@ -1818,7 +1828,9 @@ static void edge_bulk_out_callback(struct urb *urb)
        }
 
        /* send any buffered data */
-       edge_send(port->port.tty);
+       tty = tty_port_tty_get(&port->port);
+       edge_send(tty);
+       tty_kref_put(tty);
 }
 
 static int edge_open(struct tty_struct *tty,
@@ -1876,7 +1888,7 @@ static int edge_open(struct tty_struct *tty,
 
        /* set up the port settings */
        if (tty)
-               edge_set_termios(tty, port, port->port.tty->termios);
+               edge_set_termios(tty, port, tty->termios);
 
        /* open up the port */
 
index cd9a2e138c8b35f3a3cacb4cd60525ed39d179b6..2affa9c118b2450691834141c47344ebe5dcb827 100644 (file)
@@ -764,13 +764,14 @@ static void ipaq_read_bulk_callback(struct urb *urb)
        usb_serial_debug_data(debug, &port->dev, __func__,
                                                urb->actual_length, data);
 
-       tty = port->port.tty;
+       tty = tty_port_tty_get(&port->port);
        if (tty && urb->actual_length) {
                tty_buffer_request_room(tty, urb->actual_length);
                tty_insert_flip_string(tty, data, urb->actual_length);
                tty_flip_buffer_push(tty);
                bytes_in += urb->actual_length;
        }
+       tty_kref_put(tty);
 
        /* Continue trying to always read  */
        usb_fill_bulk_urb(port->read_urb, port->serial->dev,
index a842025b9b576d4f3e8e678cf386713a9c7baf61..480cac27d646d91a09fc7e289a74b2d4fb9f2139 100644 (file)
@@ -170,12 +170,13 @@ static void ipw_read_bulk_callback(struct urb *urb)
        usb_serial_debug_data(debug, &port->dev, __func__,
                                        urb->actual_length, data);
 
-       tty = port->port.tty;
+       tty = tty_port_tty_get(&port->port);
        if (tty && urb->actual_length) {
                tty_buffer_request_room(tty, urb->actual_length);
                tty_insert_flip_string(tty, data, urb->actual_length);
                tty_flip_buffer_push(tty);
        }
+       tty_kref_put(tty);
 
        /* Continue trying to always read  */
        usb_fill_bulk_urb(port->read_urb, port->serial->dev,
index e59155c6607da7c58dabe8b7d5b83b7957816358..45d4043e04abbcd429a27c4204ee01b8b70105d2 100644 (file)
@@ -465,11 +465,12 @@ static void ir_read_bulk_callback(struct urb *urb)
                        ir_baud = *data & 0x0f;
                usb_serial_debug_data(debug, &port->dev, __func__,
                                                urb->actual_length, data);
-               tty = port->port.tty;
+               tty = tty_port_tty_get(&port->port);
                if (tty_buffer_request_room(tty, urb->actual_length - 1)) {
                        tty_insert_flip_string(tty, data+1, urb->actual_length - 1);
                        tty_flip_buffer_push(tty);
                }
+               tty_kref_put(tty);
 
                /*
                 * No break here.
index ddff37fa633904b28cb7a8ffe41c2a4804491c5f..53710aa7eadd96d7c6f1e535d513465815a7bceb 100644 (file)
@@ -629,13 +629,14 @@ static void read_buf_callback(struct urb *urb)
        }
 
        dbg("%s - %i chars to write", __func__, urb->actual_length);
-       tty = port->port.tty;
+       tty = tty_port_tty_get(&port->port);
        if (data == NULL)
                dbg("%s - data is NULL !!!", __func__);
        if (tty && urb->actual_length && data) {
                tty_insert_flip_string(tty, data, urb->actual_length);
                tty_flip_buffer_push(tty);
        }
+       tty_kref_put(tty);
        iuu_led_activity_on(urb);
 }
 
index 704716f6f6d378c825920c213f3cedd7585b0ab5..15447af48691b5b79140c3303744b868359b1390 100644 (file)
@@ -430,7 +430,7 @@ static void usa26_indat_callback(struct urb *urb)
        }
 
        port =  urb->context;
-       tty = port->port.tty;
+       tty = tty_port_tty_get(&port->port);
        if (tty && urb->actual_length) {
                /* 0x80 bit is error flag */
                if ((data[0] & 0x80) == 0) {
@@ -459,6 +459,7 @@ static void usa26_indat_callback(struct urb *urb)
                }
                tty_flip_buffer_push(tty);
        }
+       tty_kref_put(tty);
 
        /* Resubmit urb so we continue receiving */
        urb->dev = port->serial->dev;
@@ -513,6 +514,7 @@ static void usa26_instat_callback(struct urb *urb)
        struct usb_serial                       *serial;
        struct usb_serial_port                  *port;
        struct keyspan_port_private             *p_priv;
+       struct tty_struct                       *tty;
        int old_dcd_state, err;
        int status = urb->status;
 
@@ -553,12 +555,11 @@ static void       usa26_instat_callback(struct urb *urb)
        p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0);
        p_priv->ri_state = ((msg->ri) ? 1 : 0);
 
-       if (port->port.tty && !C_CLOCAL(port->port.tty)
-           && old_dcd_state != p_priv->dcd_state) {
-               if (old_dcd_state)
-                       tty_hangup(port->port.tty);
-               /*  else */
-               /*      wake_up_interruptible(&p_priv->open_wait); */
+       if (old_dcd_state != p_priv->dcd_state) {
+               tty = tty_port_tty_get(&port->port);
+               if (tty && !C_CLOCAL(tty))
+                       tty_hangup(tty);
+               tty_kref_put(tty);
        }
 
        /* Resubmit urb so we continue receiving */
@@ -604,11 +605,12 @@ static void usa28_indat_callback(struct urb *urb)
                p_priv = usb_get_serial_port_data(port);
                data = urb->transfer_buffer;
 
-               tty = port->port.tty;
-               if (urb->actual_length) {
+               tty =tty_port_tty_get(&port->port);
+               if (tty && urb->actual_length) {
                        tty_insert_flip_string(tty, data, urb->actual_length);
                        tty_flip_buffer_push(tty);
                }
+               tty_kref_put(tty);
 
                /* Resubmit urb so we continue receiving */
                urb->dev = port->serial->dev;
@@ -652,6 +654,7 @@ static void usa28_instat_callback(struct urb *urb)
        struct usb_serial                       *serial;
        struct usb_serial_port                  *port;
        struct keyspan_port_private             *p_priv;
+       struct tty_struct                       *tty;
        int old_dcd_state;
        int status = urb->status;
 
@@ -689,12 +692,11 @@ static void       usa28_instat_callback(struct urb *urb)
        p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
        p_priv->ri_state = ((msg->ri) ? 1 : 0);
 
-       if (port->port.tty && !C_CLOCAL(port->port.tty)
-           && old_dcd_state != p_priv->dcd_state) {
-               if (old_dcd_state)
-                       tty_hangup(port->port.tty);
-               /*  else */
-               /*      wake_up_interruptible(&p_priv->open_wait); */
+       if( old_dcd_state != p_priv->dcd_state && old_dcd_state) {
+               tty = tty_port_tty_get(&port->port);
+               if (tty && !C_CLOCAL(tty)) 
+                       tty_hangup(tty);
+               tty_kref_put(tty);
        }
 
                /* Resubmit urb so we continue receiving */
@@ -785,12 +787,11 @@ static void       usa49_instat_callback(struct urb *urb)
        p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
        p_priv->ri_state = ((msg->ri) ? 1 : 0);
 
-       if (port->port.tty && !C_CLOCAL(port->port.tty)
-           && old_dcd_state != p_priv->dcd_state) {
-               if (old_dcd_state)
-                       tty_hangup(port->port.tty);
-               /*  else */
-               /*      wake_up_interruptible(&p_priv->open_wait); */
+       if (old_dcd_state != p_priv->dcd_state && old_dcd_state) {
+               struct tty_struct *tty = tty_port_tty_get(&port->port);
+               if (tty && !C_CLOCAL(tty))
+                       tty_hangup(tty);
+               tty_kref_put(tty);
        }
 
        /* Resubmit urb so we continue receiving */
@@ -827,7 +828,7 @@ static void usa49_indat_callback(struct urb *urb)
        }
 
        port =  urb->context;
-       tty = port->port.tty;
+       tty = tty_port_tty_get(&port->port);
        if (tty && urb->actual_length) {
                /* 0x80 bit is error flag */
                if ((data[0] & 0x80) == 0) {
@@ -850,6 +851,7 @@ static void usa49_indat_callback(struct urb *urb)
                }
                tty_flip_buffer_push(tty);
        }
+       tty_kref_put(tty);
 
        /* Resubmit urb so we continue receiving */
        urb->dev = port->serial->dev;
@@ -893,7 +895,7 @@ static void usa49wg_indat_callback(struct urb *urb)
                                return;
                        }
                        port = serial->port[data[i++]];
-                       tty = port->port.tty;
+                       tty = tty_port_tty_get(&port->port);
                        len = data[i++];
 
                        /* 0x80 bit is error flag */
@@ -927,6 +929,7 @@ static void usa49wg_indat_callback(struct urb *urb)
                        }
                        if (port->port.count)
                                tty_flip_buffer_push(tty);
+                       tty_kref_put(tty);
                }
        }
 
@@ -967,8 +970,8 @@ static void usa90_indat_callback(struct urb *urb)
        port =  urb->context;
        p_priv = usb_get_serial_port_data(port);
 
-       tty = port->port.tty;
        if (urb->actual_length) {
+               tty = tty_port_tty_get(&port->port);
                /* if current mode is DMA, looks like usa28 format
                   otherwise looks like usa26 data format */
 
@@ -1004,6 +1007,7 @@ static void usa90_indat_callback(struct urb *urb)
                        }
                }
                tty_flip_buffer_push(tty);
+               tty_kref_put(tty);
        }
 
        /* Resubmit urb so we continue receiving */
@@ -1025,6 +1029,7 @@ static void       usa90_instat_callback(struct urb *urb)
        struct usb_serial                       *serial;
        struct usb_serial_port                  *port;
        struct keyspan_port_private             *p_priv;
+       struct tty_struct                       *tty;
        int old_dcd_state, err;
        int status = urb->status;
 
@@ -1053,12 +1058,11 @@ static void     usa90_instat_callback(struct urb *urb)
        p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
        p_priv->ri_state = ((msg->ri) ? 1 : 0);
 
-       if (port->port.tty && !C_CLOCAL(port->port.tty)
-           && old_dcd_state != p_priv->dcd_state) {
-               if (old_dcd_state)
-                       tty_hangup(port->port.tty);
-               /*  else */
-               /*      wake_up_interruptible(&p_priv->open_wait); */
+       if (old_dcd_state != p_priv->dcd_state && old_dcd_state) {
+               tty = tty_port_tty_get(&port->port);
+               if (tty && !C_CLOCAL(tty))
+                       tty_hangup(tty);
+               tty_kref_put(tty);
        }
 
        /* Resubmit urb so we continue receiving */
@@ -1130,12 +1134,11 @@ static void     usa67_instat_callback(struct urb *urb)
        p_priv->cts_state = ((msg->hskia_cts) ? 1 : 0);
        p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0);
 
-       if (port->port.tty && !C_CLOCAL(port->port.tty)
-           && old_dcd_state != p_priv->dcd_state) {
-               if (old_dcd_state)
-                       tty_hangup(port->port.tty);
-               /*  else */
-               /*      wake_up_interruptible(&p_priv->open_wait); */
+       if (old_dcd_state != p_priv->dcd_state && old_dcd_state) {
+               struct tty_struct *tty = tty_port_tty_get(&port->port);
+               if (tty && !C_CLOCAL(tty))
+                       tty_hangup(tty);
+               tty_kref_put(tty);
        }
 
        /* Resubmit urb so we continue receiving */
@@ -1332,7 +1335,7 @@ static void keyspan_close(struct tty_struct *tty,
                        stop_urb(p_priv->out_urbs[i]);
                }
        }
-       port->port.tty = NULL;
+       tty_port_tty_set(&port->port, NULL);
 }
 
 /* download the firmware to a pre-renumeration device */
index 040040a267d970ff0fe97b057fb1eb7cb8f6df33..99e9a14c5bf65979ddfb2de5c03dc2c50e1b8968 100644 (file)
@@ -172,8 +172,9 @@ static void keyspan_pda_wakeup_write(struct work_struct *work)
        struct keyspan_pda_private *priv =
                container_of(work, struct keyspan_pda_private, wakeup_work);
        struct usb_serial_port *port = priv->port;
-
-       tty_wakeup(port->port.tty);
+       struct tty_struct *tty = tty_port_tty_get(&port->port);
+       tty_wakeup(tty);
+       tty_kref_put(tty);
 }
 
 static void keyspan_pda_request_unthrottle(struct work_struct *work)
@@ -205,7 +206,7 @@ static void keyspan_pda_request_unthrottle(struct work_struct *work)
 static void keyspan_pda_rx_interrupt(struct urb *urb)
 {
        struct usb_serial_port *port = urb->context;
-       struct tty_struct *tty = port->port.tty;
+       struct tty_struct *tty = tty_port_tty_get(&port->port);
        unsigned char *data = urb->transfer_buffer;
        int retval;
        int status = urb->status;
@@ -222,7 +223,7 @@ static void keyspan_pda_rx_interrupt(struct urb *urb)
                /* this urb is terminated, clean up */
                dbg("%s - urb shutting down with status: %d",
                    __func__, status);
-               return;
+               goto out;
        default:
                dbg("%s - nonzero urb status received: %d",
                    __func__, status);
@@ -261,8 +262,11 @@ static void keyspan_pda_rx_interrupt(struct urb *urb)
 exit:
        retval = usb_submit_urb(urb, GFP_ATOMIC);
        if (retval)
-               err("%s - usb_submit_urb failed with result %d",
-                    __func__, retval);
+               dev_err(&port->dev,
+                       "%s - usb_submit_urb failed with result %d",
+                       __func__, retval);
+out:
+       tty_kref_put(tty);                   
 }
 
 
index b84dddc71124546ec0fd968ae03748975dae6f1a..ff3a07f5102fe11a70e11bfc5c3959116b814d78 100644 (file)
@@ -658,7 +658,7 @@ static void klsi_105_read_bulk_callback(struct urb *urb)
        } else {
                int bytes_sent = ((__u8 *) data)[0] +
                                 ((unsigned int) ((__u8 *) data)[1] << 8);
-               tty = port->port.tty;
+               tty = tty_port_tty_get(&port->port);
                /* we should immediately resubmit the URB, before attempting
                 * to pass the data on to the tty layer. But that needs locking
                 * against re-entry an then mixed-up data because of
@@ -679,6 +679,7 @@ static void klsi_105_read_bulk_callback(struct urb *urb)
                tty_buffer_request_room(tty, bytes_sent);
                tty_insert_flip_string(tty, data + 2, bytes_sent);
                tty_flip_buffer_push(tty);
+               tty_kref_put(tty);
 
                /* again lockless, but debug info only */
                priv->bytes_in += bytes_sent;
index deba28ec77e8e43cab07691bf17ed68624b9d517..cfcf37c2b95703014f39436539619192a11864cc 100644 (file)
@@ -383,7 +383,7 @@ static void kobil_read_int_callback(struct urb *urb)
                return;
        }
 
-       tty = port->port.tty;
+       tty = tty_port_tty_get(&port->port);
        if (urb->actual_length) {
 
                /* BEGIN DEBUG */
@@ -405,6 +405,7 @@ static void kobil_read_int_callback(struct urb *urb)
                tty_insert_flip_string(tty, data, urb->actual_length);
                tty_flip_buffer_push(tty);
        }
+       tty_kref_put(tty);
        /* someone sets the dev to 0 if the close method has been called */
        port->interrupt_in_urb->dev = port->serial->dev;
 
index 0ded8bd6ec8546a9ff694b2e002ab4b2b6f3758e..9b2cef81cde0284deada9dea2a6faebbee15a43f 100644 (file)
@@ -563,10 +563,11 @@ static void mct_u232_read_int_callback(struct urb *urb)
         * Work-a-round: handle the 'usual' bulk-in pipe here
         */
        if (urb->transfer_buffer_length > 2) {
-               tty = port->port.tty;
+               tty = tty_port_tty_get(&port->port);
                if (urb->actual_length) {
                        tty_insert_flip_string(tty, data, urb->actual_length);
                        tty_flip_buffer_push(tty);
+                       tty_kref_put(tty);
                }
                goto exit;
        }
@@ -591,7 +592,7 @@ static void mct_u232_read_int_callback(struct urb *urb)
         * to look in to this before committing any code.
         */
        if (priv->last_lsr & MCT_U232_LSR_ERR) {
-               tty = port->port.tty;
+               tty = tty_port_tty_get(&port->port);
                /* Overrun Error */
                if (priv->last_lsr & MCT_U232_LSR_OE) {
                }
@@ -604,6 +605,7 @@ static void mct_u232_read_int_callback(struct urb *urb)
                /* Break Indicator */
                if (priv->last_lsr & MCT_U232_LSR_BI) {
                }
+               tty_kref_put(tty);
        }
 #endif
        spin_unlock_irqrestore(&priv->lock, flags);
index 7c4917d77c0a4bf5583ddb53806dae79cb308f9b..7b538caec37fa6fc91148a10a157babcb4984fca 100644 (file)
@@ -216,12 +216,13 @@ static void mos7720_bulk_in_callback(struct urb *urb)
 
        data = urb->transfer_buffer;
 
-       tty = port->port.tty;
+       tty = tty_port_tty_get(&port->port);
        if (tty && urb->actual_length) {
                tty_buffer_request_room(tty, urb->actual_length);
                tty_insert_flip_string(tty, data, urb->actual_length);
                tty_flip_buffer_push(tty);
        }
+       tty_kref_put(tty);
 
        if (!port->read_urb) {
                dbg("URB KILLED !!!");
@@ -262,10 +263,11 @@ static void mos7720_bulk_out_data_callback(struct urb *urb)
 
        dbg("Entering .........");
 
-       tty = mos7720_port->port->port.tty;
+       tty = tty_port_tty_get(&mos7720_port->port->port);
 
        if (tty && mos7720_port->open)
                tty_wakeup(tty);
+       tty_kref_put(tty);
 }
 
 /*
@@ -1267,29 +1269,6 @@ static int get_lsr_info(struct tty_struct *tty,
        return 0;
 }
 
-/*
- * get_number_bytes_avail - get number of bytes available
- *
- * Purpose: Let user call ioctl to get the count of number of bytes available.
- */
-static int get_number_bytes_avail(struct moschip_port *mos7720_port,
-                                 unsigned int __user *value)
-{
-       unsigned int result = 0;
-       struct tty_struct *tty = mos7720_port->port->port.tty;
-
-       if (!tty)
-               return -ENOIOCTLCMD;
-
-       result = tty->read_cnt;
-
-       dbg("%s(%d) = %d", __func__,  mos7720_port->port->number, result);
-       if (copy_to_user(value, &result, sizeof(int)))
-               return -EFAULT;
-
-       return -ENOIOCTLCMD;
-}
-
 static int set_modem_info(struct moschip_port *mos7720_port, unsigned int cmd,
                          unsigned int __user *value)
 {
@@ -1409,13 +1388,6 @@ static int mos7720_ioctl(struct tty_struct *tty, struct file *file,
        dbg("%s - port %d, cmd = 0x%x", __func__, port->number, cmd);
 
        switch (cmd) {
-       case TIOCINQ:
-               /* return number of bytes available */
-               dbg("%s (%d) TIOCINQ", __func__,  port->number);
-               return get_number_bytes_avail(mos7720_port,
-                                             (unsigned int __user *)arg);
-               break;
-
        case TIOCSERGETLSR:
                dbg("%s (%d) TIOCSERGETLSR", __func__,  port->number);
                return get_lsr_info(tty, mos7720_port,
index 09d82062b97384f2402feda9f7401d75a76fb407..60543d79ef56b643d10b0ef78e0206cc717ae631 100644 (file)
@@ -709,12 +709,13 @@ static void mos7840_bulk_in_callback(struct urb *urb)
        dbg("%s", "Entering ........... \n");
 
        if (urb->actual_length) {
-               tty = mos7840_port->port->port.tty;
+               tty = tty_port_tty_get(&mos7840_port->port->port);
                if (tty) {
                        tty_buffer_request_room(tty, urb->actual_length);
                        tty_insert_flip_string(tty, data, urb->actual_length);
                        dbg(" %s \n", data);
                        tty_flip_buffer_push(tty);
+                       tty_kref_put(tty);
                }
                mos7840_port->icount.rx += urb->actual_length;
                smp_wmb();
@@ -773,10 +774,10 @@ static void mos7840_bulk_out_data_callback(struct urb *urb)
 
        dbg("%s \n", "Entering .........");
 
-       tty = mos7840_port->port->port.tty;
-
+       tty = tty_port_tty_get(&mos7840_port->port->port);
        if (tty && mos7840_port->open)
                tty_wakeup(tty);
+       tty_kref_put(tty);
 
 }
 
index d6736531a0fab1be65f8fe78a01ffb3bc535a207..bcdcbb822705fd952863dcd5d041abef4d8daad3 100644 (file)
@@ -64,12 +64,13 @@ static void navman_read_int_callback(struct urb *urb)
        usb_serial_debug_data(debug, &port->dev, __func__,
                              urb->actual_length, data);
 
-       tty = port->port.tty;
+       tty = tty_port_tty_get(&port->port);
        if (tty && urb->actual_length) {
                tty_buffer_request_room(tty, urb->actual_length);
                tty_insert_flip_string(tty, data, urb->actual_length);
                tty_flip_buffer_push(tty);
        }
+       tty_kref_put(tty);
 
 exit:
        result = usb_submit_urb(urb, GFP_ATOMIC);
index ae8e227f3db2c940a9cd0fb65b1be4641162ac95..c4d70b0f1e48cd8026805aa2c47660b46d25b237 100644 (file)
@@ -172,7 +172,7 @@ static int omninet_open(struct tty_struct *tty,
        dbg("%s - port %d", __func__, port->number);
 
        wport = serial->port[1];
-       wport->port.tty = tty;          /* FIXME */
+       tty_port_tty_set(&wport->port, tty);
 
        /* Start reading from the device */
        usb_fill_bulk_urb(port->read_urb, serial->dev,
@@ -229,9 +229,11 @@ static void omninet_read_bulk_callback(struct urb *urb)
        }
 
        if (urb->actual_length && header->oh_len) {
-               tty_insert_flip_string(port->port.tty,
-                       data + OMNINET_DATAOFFSET, header->oh_len);
-               tty_flip_buffer_push(port->port.tty);
+               struct tty_struct *tty = tty_port_tty_get(&port->port);
+               tty_insert_flip_string(tty, data + OMNINET_DATAOFFSET,
+                                                       header->oh_len);
+               tty_flip_buffer_push(tty);
+               tty_kref_put(tty);
        }
 
        /* Continue trying to always read  */
index 73f8277f88f2d26d57dafa9604f4eae5cb0468a9..6b1727e751e3bbc03e0bc5809fef36e44a991d07 100644 (file)
@@ -571,14 +571,14 @@ static void option_indat_callback(struct urb *urb)
                dbg("%s: nonzero status: %d on endpoint %02x.",
                    __func__, status, endpoint);
        } else {
-               tty = port->port.tty;
+               tty = tty_port_tty_get(&port->port);
                if (urb->actual_length) {
                        tty_buffer_request_room(tty, urb->actual_length);
                        tty_insert_flip_string(tty, data, urb->actual_length);
                        tty_flip_buffer_push(tty);
-               } else {
+               } else 
                        dbg("%s: empty read urb received", __func__);
-               }
+               tty_kref_put(tty);
 
                /* Resubmit urb so we continue receiving */
                if (port->port.count && status != -ESHUTDOWN) {
@@ -647,9 +647,13 @@ static void option_instat_callback(struct urb *urb)
                        portdata->dsr_state = ((signals & 0x02) ? 1 : 0);
                        portdata->ri_state = ((signals & 0x08) ? 1 : 0);
 
-                       if (port->port.tty && !C_CLOCAL(port->port.tty) &&
-                                       old_dcd_state && !portdata->dcd_state)
-                               tty_hangup(port->port.tty);
+                       if (old_dcd_state && !portdata->dcd_state) {
+                               struct tty_struct *tty =
+                                               tty_port_tty_get(&port->port);
+                               if (tty && !C_CLOCAL(tty))
+                                       tty_hangup(tty);
+                               tty_kref_put(tty);
+                       }
                } else {
                        dbg("%s: type %x req %x", __func__,
                                req_pkt->bRequestType, req_pkt->bRequest);
@@ -793,7 +797,7 @@ static void option_close(struct tty_struct *tty,
                for (i = 0; i < N_OUT_URB; i++)
                        usb_kill_urb(portdata->out_urbs[i]);
        }
-       port->port.tty = NULL;  /* FIXME */
+       tty_port_tty_set(&port->port, NULL);
 }
 
 /* Helper functions used by option_setup_urbs */
index 81db5715ee25ef5d0769494a11318c4cf866e0ad..ba551f00f16ff1ec30fbcd90422f1e1112e8c00a 100644 (file)
@@ -224,10 +224,6 @@ struct oti6858_private {
        struct usb_serial_port *port;   /* USB port with which associated */
 };
 
-#undef dbg
-/* #define dbg(format, arg...) printk(KERN_INFO "%s: " format "\n", __FILE__, ## arg) */
-#define dbg(format, arg...) printk(KERN_INFO "" format "\n", ## arg)
-
 static void setup_line(struct work_struct *work)
 {
        struct oti6858_private *priv = container_of(work,
@@ -1002,11 +998,12 @@ static void oti6858_read_bulk_callback(struct urb *urb)
                return;
        }
 
-       tty = port->port.tty;
+       tty = tty_port_tty_get(&port->port);
        if (tty != NULL && urb->actual_length > 0) {
                tty_insert_flip_string(tty, data, urb->actual_length);
                tty_flip_buffer_push(tty);
        }
+       tty_kref_put(tty);
 
        /* schedule the interrupt urb if we are still open */
        if (port->port.count != 0) {
index 1ede1441cb1b8aca43e699d3dbc0d1d45d9b5431..908437847165b4a34d26468891a273f26bf62ab2 100644 (file)
@@ -154,7 +154,6 @@ struct pl2303_private {
        wait_queue_head_t delta_msr_wait;
        u8 line_control;
        u8 line_status;
-       u8 termios_initialized;
        enum pl2303_type type;
 };
 
@@ -526,16 +525,6 @@ static void pl2303_set_termios(struct tty_struct *tty,
 
        dbg("%s -  port %d", __func__, port->number);
 
-       spin_lock_irqsave(&priv->lock, flags);
-       if (!priv->termios_initialized) {
-               *(tty->termios) = tty_std_termios;
-               tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
-               tty->termios->c_ispeed = 9600;
-               tty->termios->c_ospeed = 9600;
-               priv->termios_initialized = 1;
-       }
-       spin_unlock_irqrestore(&priv->lock, flags);
-
        /* The PL2303 is reported to lose bytes if you change
           serial settings even to the same values as before. Thus
           we actually need to filter in this specific case */
@@ -1057,7 +1046,7 @@ static void pl2303_read_bulk_callback(struct urb *urb)
                tty_flag = TTY_FRAME;
        dbg("%s - tty_flag = %d", __func__, tty_flag);
 
-       tty = port->port.tty;
+       tty = tty_port_tty_get(&port->port);
        if (tty && urb->actual_length) {
                tty_buffer_request_room(tty, urb->actual_length + 1);
                /* overrun is special, not associated with a char */
@@ -1067,7 +1056,7 @@ static void pl2303_read_bulk_callback(struct urb *urb)
                        tty_insert_flip_char(tty, data[i], tty_flag);
                tty_flip_buffer_push(tty);
        }
-
+       tty_kref_put(tty);
        /* Schedule the next read _if_ we are still open */
        if (port->port.count) {
                urb->dev = port->serial->dev;
index def52d07a4ea34f817c03b60ecc827655fd05d3a..72903ac9f5c0e1fff02eafbebdcfc6e356ea1e3c 100644 (file)
@@ -217,6 +217,7 @@ static void safe_read_bulk_callback(struct urb *urb)
        struct usb_serial_port *port =  urb->context;
        unsigned char *data = urb->transfer_buffer;
        unsigned char length = urb->actual_length;
+       struct tty_struct *tty;
        int result;
        int status = urb->status;
 
@@ -242,6 +243,7 @@ static void safe_read_bulk_callback(struct urb *urb)
                printk("\n");
        }
 #endif
+       tty = tty_port_tty_get(&port->port);
        if (safe) {
                __u16 fcs;
                fcs = fcs_compute10(data, length, CRC10_INITFCS);
@@ -250,9 +252,9 @@ static void safe_read_bulk_callback(struct urb *urb)
                        if (actual_length <= (length - 2)) {
                                info("%s - actual: %d", __func__,
                                                        actual_length);
-                               tty_insert_flip_string(port->port.tty,
+                               tty_insert_flip_string(tty,
                                                        data, actual_length);
-                               tty_flip_buffer_push(port->port.tty);
+                               tty_flip_buffer_push(tty);
                        } else {
                                err("%s - inconsistent lengths %d:%d",
                                        __func__, actual_length, length);
@@ -261,9 +263,10 @@ static void safe_read_bulk_callback(struct urb *urb)
                        err("%s - bad CRC %x", __func__, fcs);
                }
        } else {
-               tty_insert_flip_string(port->port.tty, data, length);
-               tty_flip_buffer_push(port->port.tty);
+               tty_insert_flip_string(tty, data, length);
+               tty_flip_buffer_push(tty);
        }
+       tty_kref_put(tty);
 
        /* Continue trying to always read  */
        usb_fill_bulk_urb(urb, port->serial->dev,
index ea1a103c99bea9f23d3a4eb7fb4f846ccbed987f..8b9eaf38367905efc44ae1a6f7bdb216996b1a68 100644 (file)
@@ -440,14 +440,14 @@ static void sierra_indat_callback(struct urb *urb)
                dbg("%s: nonzero status: %d on endpoint %02x.",
                    __func__, status, endpoint);
        } else {
-               tty = port->port.tty;
                if (urb->actual_length) {
+               tty = tty_port_tty_get(&port->port);
                        tty_buffer_request_room(tty, urb->actual_length);
                        tty_insert_flip_string(tty, data, urb->actual_length);
                        tty_flip_buffer_push(tty);
-               } else {
+                       tty_kref_put(tty);
+               } else
                        dbg("%s: empty read urb received", __func__);
-               }
 
                /* Resubmit urb so we continue receiving */
                if (port->port.count && status != -ESHUTDOWN) {
@@ -485,6 +485,7 @@ static void sierra_instat_callback(struct urb *urb)
                        unsigned char signals = *((unsigned char *)
                                        urb->transfer_buffer +
                                        sizeof(struct usb_ctrlrequest));
+                       struct tty_struct *tty;
 
                        dbg("%s: signal x%x", __func__, signals);
 
@@ -494,9 +495,11 @@ static void sierra_instat_callback(struct urb *urb)
                        portdata->dsr_state = ((signals & 0x02) ? 1 : 0);
                        portdata->ri_state = ((signals & 0x08) ? 1 : 0);
 
-                       if (port->port.tty && !C_CLOCAL(port->port.tty) &&
+                       tty = tty_port_tty_get(&port->port);
+                       if (tty && !C_CLOCAL(tty) &&
                                        old_dcd_state && !portdata->dcd_state)
-                               tty_hangup(port->port.tty);
+                               tty_hangup(tty);
+                       tty_kref_put(tty);
                } else {
                        dbg("%s: type %x req %x", __func__,
                                req_pkt->bRequestType, req_pkt->bRequest);
@@ -616,8 +619,7 @@ static void sierra_close(struct tty_struct *tty,
        }
 
        usb_kill_urb(port->interrupt_in_urb);
-
-       port->port.tty = NULL;  /* FIXME */
+       tty_port_tty_set(&port->port, NULL);
 }
 
 static int sierra_startup(struct usb_serial *serial)
index 283cf6b36b2c0cca7f77c7ce0409c4420faa6753..1533d6e122387317b07576a74239009bc3be9296 100644 (file)
@@ -755,7 +755,7 @@ static void spcp8x5_read_bulk_callback(struct urb *urb)
                tty_flag = TTY_FRAME;
        dev_dbg(&port->dev, "tty_flag = %d\n", tty_flag);
 
-       tty = port->port.tty;
+       tty = tty_port_tty_get(&port->port);
        if (tty && urb->actual_length) {
                tty_buffer_request_room(tty, urb->actual_length + 1);
                /* overrun is special, not associated with a char */
@@ -765,6 +765,7 @@ static void spcp8x5_read_bulk_callback(struct urb *urb)
                        tty_insert_flip_char(tty, data[i], tty_flag);
                tty_flip_buffer_push(tty);
        }
+       tty_kref_put(tty);
 
        /* Schedule the next read _if_ we are still open */
        if (port->port.count) {
index 9a3e495c769cc92f7abaa59d33d7138fe2e73f73..c90237d48b0e6e8a22e59498e78bfff83c8bf9ed 100644 (file)
@@ -179,7 +179,7 @@ static int ti_set_mcr(struct ti_port *tport, unsigned int mcr);
 static int ti_get_lsr(struct ti_port *tport);
 static int ti_get_serial_info(struct ti_port *tport,
        struct serial_struct __user *ret_arg);
-static int ti_set_serial_info(struct ti_port *tport,
+static int ti_set_serial_info(struct tty_struct *tty, struct ti_port *tport,
        struct serial_struct __user *new_arg);
 static void ti_handle_new_msr(struct ti_port *tport, __u8 msr);
 
@@ -857,8 +857,8 @@ static int ti_ioctl(struct tty_struct *tty, struct file *file,
                                (struct serial_struct __user *)arg);
        case TIOCSSERIAL:
                dbg("%s - (%d) TIOCSSERIAL", __func__, port->number);
-               return ti_set_serial_info(tport,
-                                       (struct serial_struct __user *)arg);
+               return ti_set_serial_info(tty, tport,
+                               (struct serial_struct __user *)arg);
        case TIOCMIWAIT:
                dbg("%s - (%d) TIOCMIWAIT", __func__, port->number);
                cprev = tport->tp_icount;
@@ -1211,6 +1211,7 @@ static void ti_bulk_in_callback(struct urb *urb)
        struct device *dev = &urb->dev->dev;
        int status = urb->status;
        int retval = 0;
+       struct tty_struct *tty;
 
        dbg("%s", __func__);
 
@@ -1239,20 +1240,22 @@ static void ti_bulk_in_callback(struct urb *urb)
                return;
        }
 
-       if (port->port.tty && urb->actual_length) {
+       tty = tty_port_tty_get(&port->port);
+       if (tty && urb->actual_length) {
                usb_serial_debug_data(debug, dev, __func__,
                        urb->actual_length, urb->transfer_buffer);
 
                if (!tport->tp_is_open)
                        dbg("%s - port closed, dropping data", __func__);
                else
-                       ti_recv(&urb->dev->dev, port->port.tty,
+                       ti_recv(&urb->dev->dev, tty,
                                                urb->transfer_buffer,
                                                urb->actual_length);
 
                spin_lock(&tport->tp_lock);
                tport->tp_icount.rx += urb->actual_length;
                spin_unlock(&tport->tp_lock);
+               tty_kref_put(tty);
        }
 
 exit:
@@ -1330,7 +1333,7 @@ static void ti_send(struct ti_port *tport)
 {
        int count, result;
        struct usb_serial_port *port = tport->tp_port;
-       struct tty_struct *tty = port->port.tty;        /* FIXME */
+       struct tty_struct *tty = tty_port_tty_get(&port->port); /* FIXME */
        unsigned long flags;
 
 
@@ -1338,19 +1341,15 @@ static void ti_send(struct ti_port *tport)
 
        spin_lock_irqsave(&tport->tp_lock, flags);
 
-       if (tport->tp_write_urb_in_use) {
-               spin_unlock_irqrestore(&tport->tp_lock, flags);
-               return;
-       }
+       if (tport->tp_write_urb_in_use)
+               goto unlock;
 
        count = ti_buf_get(tport->tp_write_buf,
                                port->write_urb->transfer_buffer,
                                port->bulk_out_size);
 
-       if (count == 0) {
-               spin_unlock_irqrestore(&tport->tp_lock, flags);
-               return;
-       }
+       if (count == 0)
+               goto unlock;
 
        tport->tp_write_urb_in_use = 1;
 
@@ -1380,7 +1379,13 @@ static void ti_send(struct ti_port *tport)
        /* more room in the buffer for new writes, wakeup */
        if (tty)
                tty_wakeup(tty);
+       tty_kref_put(tty);
        wake_up_interruptible(&tport->tp_write_wait);
+       return;
+unlock:
+       spin_unlock_irqrestore(&tport->tp_lock, flags);
+       tty_kref_put(tty);
+       return;
 }
 
 
@@ -1464,20 +1469,16 @@ static int ti_get_serial_info(struct ti_port *tport,
 }
 
 
-static int ti_set_serial_info(struct ti_port *tport,
+static int ti_set_serial_info(struct tty_struct *tty, struct ti_port *tport,
        struct serial_struct __user *new_arg)
 {
-       struct usb_serial_port *port = tport->tp_port;
        struct serial_struct new_serial;
 
        if (copy_from_user(&new_serial, new_arg, sizeof(new_serial)))
                return -EFAULT;
 
        tport->tp_flags = new_serial.flags & TI_SET_SERIAL_FLAGS;
-       /* FIXME */
-       if (port->port.tty)
-               port->port.tty->low_latency =
-                       (tport->tp_flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+       tty->low_latency = (tport->tp_flags & ASYNC_LOW_LATENCY) ? 1 : 0;
        tport->tp_closing_wait = new_serial.closing_wait;
 
        return 0;
@@ -1510,7 +1511,7 @@ static void ti_handle_new_msr(struct ti_port *tport, __u8 msr)
        tport->tp_msr = msr & TI_MSR_MASK;
 
        /* handle CTS flow control */
-       tty = tport->tp_port->port.tty;
+       tty = tty_port_tty_get(&tport->tp_port->port);
        if (tty && C_CRTSCTS(tty)) {
                if (msr & TI_MSR_CTS) {
                        tty->hw_stopped = 0;
@@ -1519,6 +1520,7 @@ static void ti_handle_new_msr(struct ti_port *tport, __u8 msr)
                        tty->hw_stopped = 1;
                }
        }
+       tty_kref_put(tty);
 }
 
 
index 4f7f9e3ae0a43fe0fd630aaf4f436637383b0e4d..e7d4246027b23763e2b5ad86215a20029a10d8ed 100644 (file)
@@ -214,7 +214,7 @@ static int serial_open (struct tty_struct *tty, struct file *filp)
        /* set up our port structure making the tty driver
         * remember our port object, and us it */
        tty->driver_data = port;
-       port->port.tty = tty;
+       tty_port_tty_set(&port->port, tty);
 
        if (port->port.count == 1) {
 
@@ -246,7 +246,7 @@ bailout_module_put:
 bailout_mutex_unlock:
        port->port.count = 0;
        tty->driver_data = NULL;
-       port->port.tty = NULL;
+       tty_port_tty_set(&port->port, NULL);
        mutex_unlock(&port->mutex);
 bailout_kref_put:
        usb_serial_put(serial);
@@ -276,10 +276,11 @@ static void serial_close(struct tty_struct *tty, struct file *filp)
                port->serial->type->close(tty, port, filp);
 
        if (port->port.count == (port->console? 1 : 0)) {
-               if (port->port.tty) {
-                       if (port->port.tty->driver_data)
-                               port->port.tty->driver_data = NULL;
-                       port->port.tty = NULL;
+               struct tty_struct *tty = tty_port_tty_get(&port->port);
+               if (tty) {
+                       if (tty->driver_data)
+                               tty->driver_data = NULL;
+                       tty_port_tty_set(&port->port, NULL);
                }
        }
 
@@ -508,11 +509,12 @@ static void usb_serial_port_work(struct work_struct *work)
        if (!port)
                return;
 
-       tty = port->port.tty;
+       tty = tty_port_tty_get(&port->port);
        if (!tty)
                return;
 
        tty_wakeup(tty);
+       tty_kref_put(tty);
 }
 
 static void port_release(struct device *dev)
@@ -819,6 +821,7 @@ int usb_serial_probe(struct usb_interface *interface,
                port = kzalloc(sizeof(struct usb_serial_port), GFP_KERNEL);
                if (!port)
                        goto probe_error;
+               tty_port_init(&port->port);
                port->serial = serial;
                spin_lock_init(&port->lock);
                mutex_init(&port->mutex);
@@ -1040,8 +1043,11 @@ void usb_serial_disconnect(struct usb_interface *interface)
        for (i = 0; i < serial->num_ports; ++i) {
                port = serial->port[i];
                if (port) {
-                       if (port->port.tty)
-                               tty_hangup(port->port.tty);
+                       struct tty_struct *tty = tty_port_tty_get(&port->port);
+                       if (tty) {
+                               tty_hangup(tty);
+                               tty_kref_put(tty);
+                       }
                        kill_traffic(port);
                }
        }
index cf8924f9a2cc1d461436caaefcbcfeb81b0f0168..a6d1c75a1c89eb3f4627744ee2c91a1d6b071a0f 100644 (file)
@@ -499,7 +499,7 @@ static void visor_read_bulk_callback(struct urb *urb)
        int status = urb->status;
        struct tty_struct *tty;
        int result;
-       int available_room;
+       int available_room = 0;
 
        dbg("%s - port %d", __func__, port->number);
 
@@ -512,13 +512,17 @@ static void visor_read_bulk_callback(struct urb *urb)
        usb_serial_debug_data(debug, &port->dev, __func__,
                                                urb->actual_length, data);
 
-       tty = port->port.tty;
-       if (tty && urb->actual_length) {
-               available_room = tty_buffer_request_room(tty,
+       if (urb->actual_length) {
+               tty = tty_port_tty_get(&port->port);
+               if (tty) {
+                       available_room = tty_buffer_request_room(tty,
                                                        urb->actual_length);
-               if (available_room) {
-                       tty_insert_flip_string(tty, data, available_room);
-                       tty_flip_buffer_push(tty);
+                       if (available_room) {
+                               tty_insert_flip_string(tty, data,
+                                                       available_room);
+                               tty_flip_buffer_push(tty);
+                       }
+                       tty_kref_put(tty);
                }
                spin_lock(&priv->lock);
                priv->bytes_in += available_room;
index 3a9d14384a4380a85ec0072d1bda7aa653ad5d7c..11c8b97a5177ad6c645861a739cc0f62f30ab667 100644 (file)
@@ -1481,7 +1481,7 @@ static void rx_data_softint(struct work_struct *work)
        struct whiteheat_private *info =
                container_of(work, struct whiteheat_private, rx_work);
        struct usb_serial_port *port = info->port;
-       struct tty_struct *tty = port->port.tty;
+       struct tty_struct *tty = tty_port_tty_get(&port->port);
        struct whiteheat_urb_wrap *wrap;
        struct urb *urb;
        unsigned long flags;
@@ -1493,7 +1493,7 @@ static void rx_data_softint(struct work_struct *work)
        spin_lock_irqsave(&info->lock, flags);
        if (info->flags & THROTTLED) {
                spin_unlock_irqrestore(&info->lock, flags);
-               return;
+               goto out;
        }
 
        list_for_each_safe(tmp, tmp2, &info->rx_urb_q) {
@@ -1513,7 +1513,7 @@ static void rx_data_softint(struct work_struct *work)
                                spin_unlock_irqrestore(&info->lock, flags);
                                tty_flip_buffer_push(tty);
                                schedule_work(&info->rx_work);
-                               return;
+                               goto out;
                        }
                        tty_insert_flip_string(tty, urb->transfer_buffer, len);
                        sent += len;
@@ -1536,6 +1536,8 @@ static void rx_data_softint(struct work_struct *work)
 
        if (sent)
                tty_flip_buffer_push(tty);
+out:
+       tty_kref_put(tty);
 }
 
 
index 385cba40ea87d4f33e2fe948f973432a8196d14e..06964af761c630295851142dac7690fc1bf11ab5 100644 (file)
@@ -111,6 +111,4 @@ module_exit(mbp_exit);
 MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>");
 MODULE_DESCRIPTION("Nvidia-based Macbook Pro Backlight Driver");
 MODULE_LICENSE("GPL");
-MODULE_ALIAS("svnAppleInc.:pnMacBookPro3,1");
-MODULE_ALIAS("svnAppleInc.:pnMacBookPro3,2");
-MODULE_ALIAS("svnAppleInc.:pnMacBookPro4,1");
+MODULE_DEVICE_TABLE(dmi, mbp_device_table);
index 4a551af6f3fc956ffc4032e4c79d16c3b61294df..17c9c5ec14c526fe0eddbf77e9771550bae6fbb8 100644 (file)
@@ -59,10 +59,12 @@ config BINFMT_SHARED_FLAT
        help
          Support FLAT shared libraries
 
+config HAVE_AOUT
+       def_bool n
+
 config BINFMT_AOUT
        tristate "Kernel support for a.out and ECOFF binaries"
-       depends on ARCH_SUPPORTS_AOUT && \
-               (X86_32 || ALPHA || ARM || M68K)
+       depends on HAVE_AOUT
        ---help---
          A.out (Assembler.OUTput) is a set of formats for libraries and
          executables used in the earliest versions of UNIX.  Linux used
index 08e28c9bb4164f5e2f549535959fd816d92521ed..3dbe2169cf36358730317f3ac563cf985c3cbc0b 100644 (file)
@@ -26,8 +26,7 @@
 #include <linux/debugfs.h>
 #include <linux/fsnotify.h>
 #include <linux/string.h>
-
-#define DEBUGFS_MAGIC  0x64626720
+#include <linux/magic.h>
 
 static struct vfsmount *debugfs_mount;
 static int debugfs_mount_count;
index 488eb424f662141488cc8a966496776fa66e2dc9..a70d5d0890c7311ba0a0b555f6c977b38eddaa4c 100644 (file)
@@ -27,6 +27,7 @@
 #define DEVPTS_SUPER_MAGIC 0x1cd1
 
 #define DEVPTS_DEFAULT_MODE 0600
+#define PTMX_MINOR     2
 
 extern int pty_limit;                  /* Config limit on Unix98 ptys */
 static DEFINE_IDA(allocated_ptys);
@@ -169,15 +170,7 @@ static struct file_system_type devpts_fs_type = {
  * to the System V naming convention
  */
 
-static struct dentry *get_node(int num)
-{
-       char s[12];
-       struct dentry *root = devpts_root;
-       mutex_lock(&root->d_inode->i_mutex);
-       return lookup_one_len(s, root, sprintf(s, "%d", num));
-}
-
-int devpts_new_index(void)
+int devpts_new_index(struct inode *ptmx_inode)
 {
        int index;
        int ida_ret;
@@ -205,20 +198,21 @@ retry:
        return index;
 }
 
-void devpts_kill_index(int idx)
+void devpts_kill_index(struct inode *ptmx_inode, int idx)
 {
        mutex_lock(&allocated_ptys_lock);
        ida_remove(&allocated_ptys, idx);
        mutex_unlock(&allocated_ptys_lock);
 }
 
-int devpts_pty_new(struct tty_struct *tty)
+int devpts_pty_new(struct inode *ptmx_inode, struct tty_struct *tty)
 {
        int number = tty->index; /* tty layer puts index from devpts_new_index() in here */
        struct tty_driver *driver = tty->driver;
        dev_t device = MKDEV(driver->major, driver->minor_start+number);
        struct dentry *dentry;
        struct inode *inode = new_inode(devpts_mnt->mnt_sb);
+       char s[12];
 
        /* We're supposed to be given the slave end of a pty */
        BUG_ON(driver->type != TTY_DRIVER_TYPE_PTY);
@@ -233,10 +227,15 @@ int devpts_pty_new(struct tty_struct *tty)
        inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
        init_special_inode(inode, S_IFCHR|config.mode, device);
        inode->i_private = tty;
+       tty->driver_data = inode;
 
-       dentry = get_node(number);
-       if (!IS_ERR(dentry) && !dentry->d_inode) {
-               d_instantiate(dentry, inode);
+       sprintf(s, "%d", number);
+
+       mutex_lock(&devpts_root->d_inode->i_mutex);
+
+       dentry = d_alloc_name(devpts_root, s);
+       if (!IS_ERR(dentry)) {
+               d_add(dentry, inode);
                fsnotify_create(devpts_root->d_inode, dentry);
        }
 
@@ -245,36 +244,31 @@ int devpts_pty_new(struct tty_struct *tty)
        return 0;
 }
 
-struct tty_struct *devpts_get_tty(int number)
+struct tty_struct *devpts_get_tty(struct inode *pts_inode, int number)
 {
-       struct dentry *dentry = get_node(number);
-       struct tty_struct *tty;
-
-       tty = NULL;
-       if (!IS_ERR(dentry)) {
-               if (dentry->d_inode)
-                       tty = dentry->d_inode->i_private;
-               dput(dentry);
-       }
+       BUG_ON(pts_inode->i_rdev == MKDEV(TTYAUX_MAJOR, PTMX_MINOR));
 
-       mutex_unlock(&devpts_root->d_inode->i_mutex);
-
-       return tty;
+       if (pts_inode->i_sb->s_magic == DEVPTS_SUPER_MAGIC)
+               return (struct tty_struct *)pts_inode->i_private;
+       return NULL;
 }
 
-void devpts_pty_kill(int number)
+void devpts_pty_kill(struct tty_struct *tty)
 {
-       struct dentry *dentry = get_node(number);
+       struct inode *inode = tty->driver_data;
+       struct dentry *dentry;
 
-       if (!IS_ERR(dentry)) {
-               struct inode *inode = dentry->d_inode;
-               if (inode) {
-                       inode->i_nlink--;
-                       d_delete(dentry);
-                       dput(dentry);
-               }
+       BUG_ON(inode->i_rdev == MKDEV(TTYAUX_MAJOR, PTMX_MINOR));
+
+       mutex_lock(&devpts_root->d_inode->i_mutex);
+
+       dentry = d_find_alias(inode);
+       if (dentry && !IS_ERR(dentry)) {
+               inode->i_nlink--;
+               d_delete(dentry);
                dput(dentry);
        }
+
        mutex_unlock(&devpts_root->d_inode->i_mutex);
 }
 
index 8ec4d6cc763317bf8403a7eae3c666ef2b97b136..ad7e59003e0445943d21f8b9f78090f7b9e19b53 100644 (file)
@@ -895,10 +895,9 @@ static void print_warning(struct dquot *dquot, const int warntype)
            warntype == QUOTA_NL_BSOFTBELOW || !need_print_warning(dquot))
                return;
 
-       mutex_lock(&tty_mutex);
        tty = get_current_tty();
        if (!tty)
-               goto out_lock;
+               return;
        tty_write_message(tty, dquot->dq_sb->s_id);
        if (warntype == QUOTA_NL_ISOFTWARN || warntype == QUOTA_NL_BSOFTWARN)
                tty_write_message(tty, ": warning, ");
@@ -926,8 +925,7 @@ static void print_warning(struct dquot *dquot, const int warntype)
                        break;
        }
        tty_write_message(tty, msg);
-out_lock:
-       mutex_unlock(&tty_mutex);
+       tty_kref_put(tty);
 }
 #endif
 
index 567b134fa1f156f1c886e488771fbcb06ab61089..73b19cfc91fc57510cc96d8863b776748550b65a 100644 (file)
@@ -341,8 +341,6 @@ static int efs_statfs(struct dentry *dentry, struct kstatfs *buf) {
                        sb->inode_blocks *
                        (EFS_BLOCKSIZE / sizeof(struct efs_dinode));
        buf->f_ffree   = sb->inode_free;        /* free inodes */
-       buf->f_fsid.val[0] = (sb->fs_magic >> 16) & 0xffff; /* fs ID */
-       buf->f_fsid.val[1] =  sb->fs_magic        & 0xffff; /* fs ID */
        buf->f_namelen = EFS_MAXNAMELEN;        /* max filename length */
 
        return 0;
index 07da9359481c720c045e2a25e154df02ba02e9ff..5596049863bf742eadb115bafe0deef35b209421 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -1141,8 +1141,7 @@ EXPORT_SYMBOL(sys_close);
 asmlinkage long sys_vhangup(void)
 {
        if (capable(CAP_SYS_TTY_CONFIG)) {
-               /* XXX: this needs locking */
-               tty_vhangup(current->signal->tty);
+               tty_vhangup_self();
                return 0;
        }
        return -EPERM;
index 73cd7a418f06e7430b76ba15564fb92472263333..50f8f0600f0657d47de7081883f7dfe0fa460b69 100644 (file)
@@ -57,3 +57,13 @@ config PROC_SYSCTL
          As it is generally a good thing, you should say Y here unless
          building a kernel for install/rescue disks or your system is very
          limited in memory.
+
+config PROC_PAGE_MONITOR
+       default y
+       depends on PROC_FS && MMU
+       bool "Enable /proc page monitoring" if EMBEDDED
+       help
+         Various /proc files exist to monitor process memory utilization:
+         /proc/pid/smaps, /proc/pid/clear_refs, /proc/pid/pagemap,
+         /proc/kpagecount, and /proc/kpageflags. Disabling these
+          interfaces will reduce the size of the kernel by approximately 4kb.
index 71c9be59c9c2574045d69c33aa024d618b681b4c..f4bc0e789539f413e080324ab8209575ba349c42 100644 (file)
 #include <asm/processor.h>
 #include "internal.h"
 
-/* Gcc optimizes away "strlen(x)" for constant x */
-#define ADDBUF(buffer, string) \
-do { memcpy(buffer, string, strlen(string)); \
-     buffer += strlen(string); } while (0)
-
 static inline void task_name(struct seq_file *m, struct task_struct *p)
 {
        int i;
@@ -261,7 +256,6 @@ static inline void task_sig(struct seq_file *m, struct task_struct *p)
        sigemptyset(&ignored);
        sigemptyset(&caught);
 
-       rcu_read_lock();
        if (lock_task_sighand(p, &flags)) {
                pending = p->pending.signal;
                shpending = p->signal->shared_pending.signal;
@@ -272,7 +266,6 @@ static inline void task_sig(struct seq_file *m, struct task_struct *p)
                qlim = p->signal->rlim[RLIMIT_SIGPENDING].rlim_cur;
                unlock_task_sighand(p, &flags);
        }
-       rcu_read_unlock();
 
        seq_printf(m, "Threads:\t%d\n", num_threads);
        seq_printf(m, "SigQ:\t%lu/%lu\n", qsize, qlim);
index a28840b11b89b5ca0b544f44ce58182544f51eef..b5918ae8ca79a7823bd6a4d3eb0ecfc0b08d30f6 100644 (file)
@@ -148,9 +148,6 @@ static unsigned int pid_entry_count_dirs(const struct pid_entry *entries,
        return count;
 }
 
-int maps_protect;
-EXPORT_SYMBOL(maps_protect);
-
 static struct fs_struct *get_fs_struct(struct task_struct *task)
 {
        struct fs_struct *fs;
@@ -164,7 +161,6 @@ static struct fs_struct *get_fs_struct(struct task_struct *task)
 
 static int get_nr_threads(struct task_struct *tsk)
 {
-       /* Must be called with the rcu_read_lock held */
        unsigned long flags;
        int count = 0;
 
@@ -471,14 +467,10 @@ static int proc_pid_limits(struct task_struct *task, char *buffer)
 
        struct rlimit rlim[RLIM_NLIMITS];
 
-       rcu_read_lock();
-       if (!lock_task_sighand(task,&flags)) {
-               rcu_read_unlock();
+       if (!lock_task_sighand(task, &flags))
                return 0;
-       }
        memcpy(rlim, task->signal->rlim, sizeof(struct rlimit) * RLIM_NLIMITS);
        unlock_task_sighand(task, &flags);
-       rcu_read_unlock();
 
        /*
         * print the file header
@@ -2443,6 +2435,13 @@ static int proc_tgid_io_accounting(struct task_struct *task, char *buffer)
 }
 #endif /* CONFIG_TASK_IO_ACCOUNTING */
 
+static int proc_pid_personality(struct seq_file *m, struct pid_namespace *ns,
+                               struct pid *pid, struct task_struct *task)
+{
+       seq_printf(m, "%08x\n", task->personality);
+       return 0;
+}
+
 /*
  * Thread groups
  */
@@ -2459,6 +2458,7 @@ static const struct pid_entry tgid_base_stuff[] = {
        REG("environ",    S_IRUSR, environ),
        INF("auxv",       S_IRUSR, pid_auxv),
        ONE("status",     S_IRUGO, pid_status),
+       ONE("personality", S_IRUSR, pid_personality),
        INF("limits",     S_IRUSR, pid_limits),
 #ifdef CONFIG_SCHED_DEBUG
        REG("sched",      S_IRUGO|S_IWUSR, pid_sched),
@@ -2794,6 +2794,7 @@ static const struct pid_entry tid_base_stuff[] = {
        REG("environ",   S_IRUSR, environ),
        INF("auxv",      S_IRUSR, pid_auxv),
        ONE("status",    S_IRUGO, pid_status),
+       ONE("personality", S_IRUSR, pid_personality),
        INF("limits",    S_IRUSR, pid_limits),
 #ifdef CONFIG_SCHED_DEBUG
        REG("sched",     S_IRUGO|S_IWUSR, pid_sched),
@@ -3088,9 +3089,7 @@ static int proc_task_getattr(struct vfsmount *mnt, struct dentry *dentry, struct
        generic_fillattr(inode, stat);
 
        if (p) {
-               rcu_read_lock();
                stat->nlink += get_nr_threads(p);
-               rcu_read_unlock();
                put_task_struct(p);
        }
 
index 8bb03f056c282ec1c0b4b256c5f4ed4551182f1c..c6b4fa7e3b49e9a2625bf3a76465c85d7df7eba2 100644 (file)
@@ -342,7 +342,7 @@ static int proc_reg_open(struct inode *inode, struct file *file)
        if (!pde->proc_fops) {
                spin_unlock(&pde->pde_unload_lock);
                kfree(pdeo);
-               return rv;
+               return -EINVAL;
        }
        pde->pde_users++;
        open = pde->proc_fops->open;
index 442202314d5322292f87328b3e62b5427b3fa77a..3bfb7b8747b3f027657a217a18ff0a7bc37b6f5d 100644 (file)
@@ -45,8 +45,6 @@ do {                                          \
 extern int nommu_vma_show(struct seq_file *, struct vm_area_struct *);
 #endif
 
-extern int maps_protect;
-
 extern int proc_tid_stat(struct seq_file *m, struct pid_namespace *ns,
                                struct pid *pid, struct task_struct *task);
 extern int proc_tgid_stat(struct seq_file *m, struct pid_namespace *ns,
index 29e20c6b1f7f75bd9d29de8589648985bad5f4a3..66c1ab87656c24adfe3342f702b4243d3c5f02da 100644 (file)
@@ -68,7 +68,6 @@
 extern int get_hardware_list(char *);
 extern int get_stram_list(char *);
 extern int get_exec_domain_list(char *);
-extern int get_dma_list(char *);
 
 static int proc_calc_metrics(char *page, char **start, off_t off,
                                 int count, int *eof, int len)
index f9a8b892718fc2f1a04ce1d169ba1667378832b5..945a81043ba223cd92206077be7847563243f89e 100644 (file)
@@ -66,7 +66,7 @@ static struct ctl_table *find_in_table(struct ctl_table *p, struct qstr *name)
        return NULL;
 }
 
-struct ctl_table_header *grab_header(struct inode *inode)
+static struct ctl_table_header *grab_header(struct inode *inode)
 {
        if (PROC_I(inode)->sysctl)
                return sysctl_head_grab(PROC_I(inode)->sysctl);
@@ -395,10 +395,10 @@ static struct dentry_operations proc_sys_dentry_operations = {
        .d_compare      = proc_sys_compare,
 };
 
-static struct proc_dir_entry *proc_sys_root;
-
 int proc_sys_init(void)
 {
+       struct proc_dir_entry *proc_sys_root;
+
        proc_sys_root = proc_mkdir("sys", NULL);
        proc_sys_root->proc_iops = &proc_sys_dir_operations;
        proc_sys_root->proc_fops = &proc_sys_dir_file_operations;
index 73d1891ee6259e41f5be2f1d8d2a16948887097d..4806830ea2a1b0515c2faf00f52a6134f0f418c1 100644 (file)
@@ -210,9 +210,6 @@ static int show_map(struct seq_file *m, void *v)
        dev_t dev = 0;
        int len;
 
-       if (maps_protect && !ptrace_may_access(task, PTRACE_MODE_READ))
-               return -EACCES;
-
        if (file) {
                struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
                dev = inode->i_sb->s_dev;
@@ -742,22 +739,11 @@ const struct file_operations proc_pagemap_operations = {
 #ifdef CONFIG_NUMA
 extern int show_numa_map(struct seq_file *m, void *v);
 
-static int show_numa_map_checked(struct seq_file *m, void *v)
-{
-       struct proc_maps_private *priv = m->private;
-       struct task_struct *task = priv->task;
-
-       if (maps_protect && !ptrace_may_access(task, PTRACE_MODE_READ))
-               return -EACCES;
-
-       return show_numa_map(m, v);
-}
-
 static const struct seq_operations proc_pid_numa_maps_op = {
         .start  = m_start,
         .next   = m_next,
         .stop   = m_stop,
-        .show   = show_numa_map_checked
+        .show   = show_numa_map,
 };
 
 static int numa_maps_open(struct inode *inode, struct file *file)
index 5d84e7121df819cd0d9eb8b9bd54973edf5b77ed..219bd79ea894f656d57f29c9b4527c41363ab3d1 100644 (file)
@@ -110,11 +110,6 @@ int task_statm(struct mm_struct *mm, int *shared, int *text,
 static int show_map(struct seq_file *m, void *_vml)
 {
        struct vm_list_struct *vml = _vml;
-       struct proc_maps_private *priv = m->private;
-       struct task_struct *task = priv->task;
-
-       if (maps_protect && !ptrace_may_access(task, PTRACE_MODE_READ))
-               return -EACCES;
 
        return nommu_vma_show(m, vml->vma);
 }
index 9ac0f5e064e09e99f58b428e933b2903a893a5b9..841368b87a29dbb89c68c4539b6203a7e0501905 100644 (file)
@@ -165,14 +165,8 @@ static ssize_t read_vmcore(struct file *file, char __user *buffer,
        return acc;
 }
 
-static int open_vmcore(struct inode *inode, struct file *filp)
-{
-       return 0;
-}
-
 const struct file_operations proc_vmcore_operations = {
        .read           = read_vmcore,
-       .open           = open_vmcore,
 };
 
 static struct vmcore* __init get_new_element(void)
diff --git a/include/asm-cris/a.out.h b/include/asm-cris/a.out.h
deleted file mode 100644 (file)
index c82e9f9..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-#ifndef __CRIS_A_OUT_H__
-#define __CRIS_A_OUT_H__
-
-/* we don't support a.out binaries on Linux/CRIS anyway, so this is
- * not really used but still needed because binfmt_elf.c for some reason
- * wants to know about a.out even if there is no interpreter available...
- */
-
-struct exec
-{
-  unsigned long a_info;                /* Use macros N_MAGIC, etc for access */
-  unsigned a_text;             /* length of text, in bytes */
-  unsigned a_data;             /* length of data, in bytes */
-  unsigned a_bss;              /* length of uninitialized data area for file, in bytes */
-  unsigned a_syms;             /* length of symbol table data in file, in bytes */
-  unsigned a_entry;            /* start address */
-  unsigned a_trsize;           /* length of relocation info for text, in bytes */
-  unsigned a_drsize;           /* length of relocation info for data, in bytes */
-};
-
-
-#define N_TRSIZE(a)    ((a).a_trsize)
-#define N_DRSIZE(a)    ((a).a_drsize)
-#define N_SYMSIZE(a)   ((a).a_syms)
-
-#endif
index 1d01043e797d94180f79ef026e5abafedc94bb1b..6129d6802149f89e269f957fa62e181d819fac60 100644 (file)
@@ -6,33 +6,64 @@
 typedef __kernel_fsid_t        fsid_t;
 #endif
 
+/*
+ * Most 64-bit platforms use 'long', while most 32-bit platforms use '__u32'.
+ * Yes, they differ in signedness as well as size.
+ * Special cases can override it for themselves -- except for S390x, which
+ * is just a little too special for us. And MIPS, which I'm not touching
+ * with a 10' pole.
+ */
+#ifndef __statfs_word
+#if BITS_PER_LONG == 64
+#define __statfs_word long
+#else
+#define __statfs_word __u32
+#endif
+#endif
+
 struct statfs {
-       __u32 f_type;
-       __u32 f_bsize;
-       __u32 f_blocks;
-       __u32 f_bfree;
-       __u32 f_bavail;
-       __u32 f_files;
-       __u32 f_ffree;
+       __statfs_word f_type;
+       __statfs_word f_bsize;
+       __statfs_word f_blocks;
+       __statfs_word f_bfree;
+       __statfs_word f_bavail;
+       __statfs_word f_files;
+       __statfs_word f_ffree;
        __kernel_fsid_t f_fsid;
-       __u32 f_namelen;
-       __u32 f_frsize;
-       __u32 f_spare[5];
+       __statfs_word f_namelen;
+       __statfs_word f_frsize;
+       __statfs_word f_spare[5];
 };
 
+/*
+ * ARM needs to avoid the 32-bit padding at the end, for consistency
+ * between EABI and OABI 
+ */
+#ifndef ARCH_PACK_STATFS64
+#define ARCH_PACK_STATFS64
+#endif
+
 struct statfs64 {
-       __u32 f_type;
-       __u32 f_bsize;
+       __statfs_word f_type;
+       __statfs_word f_bsize;
        __u64 f_blocks;
        __u64 f_bfree;
        __u64 f_bavail;
        __u64 f_files;
        __u64 f_ffree;
        __kernel_fsid_t f_fsid;
-       __u32 f_namelen;
-       __u32 f_frsize;
-       __u32 f_spare[5];
-};
+       __statfs_word f_namelen;
+       __statfs_word f_frsize;
+       __statfs_word f_spare[5];
+} ARCH_PACK_STATFS64;
+
+/* 
+ * IA64 and x86_64 need to avoid the 32-bit padding at the end,
+ * to be compatible with the i386 ABI
+ */
+#ifndef ARCH_PACK_COMPAT_STATFS64
+#define ARCH_PACK_COMPAT_STATFS64
+#endif
 
 struct compat_statfs64 {
        __u32 f_type;
@@ -46,6 +77,6 @@ struct compat_statfs64 {
        __u32 f_namelen;
        __u32 f_frsize;
        __u32 f_spare[5];
-};
+} ARCH_PACK_COMPAT_STATFS64;
 
 #endif
diff --git a/include/asm-m32r/a.out.h b/include/asm-m32r/a.out.h
deleted file mode 100644 (file)
index ab150f5..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef _ASM_M32R_A_OUT_H
-#define _ASM_M32R_A_OUT_H
-
-struct exec
-{
-  unsigned long a_info;                /* Use macros N_MAGIC, etc for access */
-  unsigned a_text;             /* length of text, in bytes */
-  unsigned a_data;             /* length of data, in bytes */
-  unsigned a_bss;              /* length of uninitialized data area for file, in bytes */
-  unsigned a_syms;             /* length of symbol table data in file, in bytes */
-  unsigned a_entry;            /* start address */
-  unsigned a_trsize;           /* length of relocation info for text, in bytes */
-  unsigned a_drsize;           /* length of relocation info for data, in bytes */
-};
-
-#define N_TRSIZE(a)    ((a).a_trsize)
-#define N_DRSIZE(a)    ((a).a_drsize)
-#define N_SYMSIZE(a)   ((a).a_syms)
-
-#endif /* _ASM_M32R_A_OUT_H */
diff --git a/include/asm-parisc/a.out.h b/include/asm-parisc/a.out.h
deleted file mode 100644 (file)
index eb04e34..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef __PARISC_A_OUT_H__
-#define __PARISC_A_OUT_H__
-
-struct exec
-{
-  unsigned int a_info;         /* Use macros N_MAGIC, etc for access */
-  unsigned a_text;             /* length of text, in bytes */
-  unsigned a_data;             /* length of data, in bytes */
-  unsigned a_bss;              /* length of uninitialized data area for file, in bytes */
-  unsigned a_syms;             /* length of symbol table data in file, in bytes */
-  unsigned a_entry;            /* start address */
-  unsigned a_trsize;           /* length of relocation info for text, in bytes */
-  unsigned a_drsize;           /* length of relocation info for data, in bytes */
-};
-
-#define N_TRSIZE(a)    ((a).a_trsize)
-#define N_DRSIZE(a)    ((a).a_drsize)
-#define N_SYMSIZE(a)   ((a).a_syms)
-
-#endif /* __A_OUT_GNU_H__ */
index 1d2b8130b23d61ee1f1be7c9430e58f682a847ef..324bea905dc6a90c760f32306f78db51600c219e 100644 (file)
@@ -1,58 +1,7 @@
 #ifndef _PARISC_STATFS_H
 #define _PARISC_STATFS_H
 
-#ifndef __KERNEL_STRICT_NAMES
-
-#include <linux/types.h>
-
-typedef __kernel_fsid_t        fsid_t;
-
-#endif
-
-/*
- * It appears that PARISC could be 64 _or_ 32 bit.
- * 64-bit fields must be explicitly 64-bit in statfs64.
- */
-struct statfs {
-       long f_type;
-       long f_bsize;
-       long f_blocks;
-       long f_bfree;
-       long f_bavail;
-       long f_files;
-       long f_ffree;
-       __kernel_fsid_t f_fsid;
-       long f_namelen;
-       long f_frsize;
-       long f_spare[5];
-};
-
-struct statfs64 {
-       long f_type;
-       long f_bsize;
-       __u64 f_blocks;
-       __u64 f_bfree;
-       __u64 f_bavail;
-       __u64 f_files;
-       __u64 f_ffree;
-       __kernel_fsid_t f_fsid;
-       long f_namelen;
-       long f_frsize;
-       long f_spare[5];
-};
-
-struct compat_statfs64 {
-       __u32 f_type;
-       __u32 f_bsize;
-       __u64 f_blocks;
-       __u64 f_bfree;
-       __u64 f_bavail;
-       __u64 f_files;
-       __u64 f_ffree;
-       __kernel_fsid_t f_fsid;
-       __u32 f_namelen;
-       __u32 f_frsize;
-       __u32 f_spare[5];
-};
+#define __statfs_word long
+#include <asm-generic/statfs.h>
 
 #endif
index ebc307817e98cc2c7999c883066d6b06134f6a16..f06adac7938c746f87b02939205b3d3370c100a0 100644 (file)
@@ -351,20 +351,16 @@ static inline void set_system_intr_gate(unsigned int n, void *addr)
        _set_gate(n, GATE_INTERRUPT, addr, 0x3, 0, __KERNEL_CS);
 }
 
-static inline void set_trap_gate(unsigned int n, void *addr)
+static inline void set_system_trap_gate(unsigned int n, void *addr)
 {
        BUG_ON((unsigned)n > 0xFF);
-       _set_gate(n, GATE_TRAP, addr, 0, 0, __KERNEL_CS);
+       _set_gate(n, GATE_TRAP, addr, 0x3, 0, __KERNEL_CS);
 }
 
-static inline void set_system_gate(unsigned int n, void *addr)
+static inline void set_trap_gate(unsigned int n, void *addr)
 {
        BUG_ON((unsigned)n > 0xFF);
-#ifdef CONFIG_X86_32
-       _set_gate(n, GATE_TRAP, addr, 0x3, 0, __KERNEL_CS);
-#else
-       _set_gate(n, GATE_INTERRUPT, addr, 0x3, 0, __KERNEL_CS);
-#endif
+       _set_gate(n, GATE_TRAP, addr, 0, 0, __KERNEL_CS);
 }
 
 static inline void set_task_gate(unsigned int n, unsigned int gdt_entry)
@@ -379,7 +375,7 @@ static inline void set_intr_gate_ist(int n, void *addr, unsigned ist)
        _set_gate(n, GATE_INTERRUPT, addr, 0, ist, __KERNEL_CS);
 }
 
-static inline void set_system_gate_ist(int n, void *addr, unsigned ist)
+static inline void set_system_intr_gate_ist(int n, void *addr, unsigned ist)
 {
        BUG_ON((unsigned)n > 0xFF);
        _set_gate(n, GATE_INTERRUPT, addr, 0x3, ist, __KERNEL_CS);
index 7b5c889d8e7d52bab6e7e0bd233c519940addc76..ed5a3caae1411017c415e11505d081d5a6374768 100644 (file)
@@ -5,6 +5,7 @@
 
 extern int parse_unisys_oem (char *oemptr);
 extern int find_unisys_acpi_oem_table(unsigned long *oem_addr);
+extern void unmap_unisys_acpi_oem_table(unsigned long oem_addr);
 extern void setup_unisys(void);
 
 #ifndef CONFIG_X86_GENERICARCH
index 784e3e759866cc0025b4dd4e9af77aeedddcdd1d..8844002da0e05df5e421846603c9b8a017bdd0a6 100644 (file)
@@ -94,10 +94,10 @@ enum fixed_addresses {
         * can have a single pgd entry and a single pte table:
         */
 #define NR_FIX_BTMAPS          64
-#define FIX_BTMAPS_NESTING     4
+#define FIX_BTMAPS_SLOTS       4
        FIX_BTMAP_END = __end_of_permanent_fixed_addresses + 256 -
                        (__end_of_permanent_fixed_addresses & 255),
-       FIX_BTMAP_BEGIN = FIX_BTMAP_END + NR_FIX_BTMAPS*FIX_BTMAPS_NESTING - 1,
+       FIX_BTMAP_BEGIN = FIX_BTMAP_END + NR_FIX_BTMAPS*FIX_BTMAPS_SLOTS - 1,
        FIX_WP_TEST,
 #ifdef CONFIG_ACPI
        FIX_ACPI_BEGIN,
index dafb24bc0424efd4b94ed18ae2ce5e1dcf4d0260..dab4751d13070491e66038af1264db9880eda7a2 100644 (file)
@@ -49,6 +49,7 @@ enum fixed_addresses {
 #ifdef CONFIG_PARAVIRT
        FIX_PARAVIRT_BOOTMAP,
 #endif
+       __end_of_permanent_fixed_addresses,
 #ifdef CONFIG_ACPI
        FIX_ACPI_BEGIN,
        FIX_ACPI_END = FIX_ACPI_BEGIN + FIX_ACPI_PAGES - 1,
@@ -56,19 +57,18 @@ enum fixed_addresses {
 #ifdef CONFIG_PROVIDE_OHCI1394_DMA_INIT
        FIX_OHCI1394_BASE,
 #endif
-       __end_of_permanent_fixed_addresses,
        /*
         * 256 temporary boot-time mappings, used by early_ioremap(),
         * before ioremap() is functional.
         *
-        * We round it up to the next 512 pages boundary so that we
+        * We round it up to the next 256 pages boundary so that we
         * can have a single pgd entry and a single pte table:
         */
 #define NR_FIX_BTMAPS          64
-#define FIX_BTMAPS_NESTING     4
-       FIX_BTMAP_END = __end_of_permanent_fixed_addresses + 512 -
-                       (__end_of_permanent_fixed_addresses & 511),
-       FIX_BTMAP_BEGIN = FIX_BTMAP_END + NR_FIX_BTMAPS*FIX_BTMAPS_NESTING - 1,
+#define FIX_BTMAPS_SLOTS       4
+       FIX_BTMAP_END = __end_of_permanent_fixed_addresses + 256 -
+                       (__end_of_permanent_fixed_addresses & 255),
+       FIX_BTMAP_BEGIN = FIX_BTMAP_END + NR_FIX_BTMAPS*FIX_BTMAPS_SLOTS - 1,
        __end_of_fixed_addresses
 };
 
index 72b7719523bfa9f26efc333ed0efb160ad37d997..a233f835e0b52a49ed02077409a7e52de22aa9a0 100644 (file)
@@ -5,20 +5,6 @@
 
 #include <linux/compiler.h>
 
-/*
- * early_ioremap() and early_iounmap() are for temporary early boot-time
- * mappings, before the real ioremap() is functional.
- * A boot-time mapping is currently limited to at most 16 pages.
- */
-#ifndef __ASSEMBLY__
-extern void early_ioremap_init(void);
-extern void early_ioremap_clear(void);
-extern void early_ioremap_reset(void);
-extern void *early_ioremap(unsigned long offset, unsigned long size);
-extern void early_iounmap(void *addr, unsigned long size);
-extern void __iomem *fix_ioremap(unsigned idx, unsigned long phys);
-#endif
-
 #define build_mmio_read(name, size, type, reg, barrier) \
 static inline type name(const volatile void __iomem *addr) \
 { type ret; asm volatile("mov" size " %1,%0":reg (ret) \
@@ -97,6 +83,7 @@ extern void early_ioremap_init(void);
 extern void early_ioremap_clear(void);
 extern void early_ioremap_reset(void);
 extern void *early_ioremap(unsigned long offset, unsigned long size);
+extern void *early_memremap(unsigned long offset, unsigned long size);
 extern void early_iounmap(void *addr, unsigned long size);
 extern void __iomem *fix_ioremap(unsigned idx, unsigned long phys);
 
index 64429e9431a8aef1089c25c8c00c18b64cd93663..ee6e086b7dfec848998c241a21b6b3baca9be5f4 100644 (file)
@@ -165,9 +165,6 @@ static inline void *phys_to_virt(unsigned long address)
 
 #include <asm-generic/iomap.h>
 
-extern void *early_ioremap(unsigned long addr, unsigned long size);
-extern void early_iounmap(void *addr, unsigned long size);
-
 /*
  * This one maps high address device memory and turns off caching for that area.
  * it's useful if some control registers are in such an area and write combining
index 33660351239968bd22205ed9e4b45e674bc67e96..06752a649044d2029c4c555f006635ff41d6b9f5 100644 (file)
 #define TCSETS2                _IOW('T', 0x2B, struct termios2)
 #define TCSETSW2       _IOW('T', 0x2C, struct termios2)
 #define TCSETSF2       _IOW('T', 0x2D, struct termios2)
+#define TIOCGRS485     0x542E
+#define TIOCSRS485     0x542F
 #define TIOCGPTN       _IOR('T', 0x30, unsigned int)
                                /* Get Pty Number (of pty-mux device) */
 #define TIOCSPTLCK     _IOW('T', 0x31, int)  /* Lock/unlock Pty */
+#define TCGETX         0x5432 /* SYS5 TCGETX compatibility */
+#define TCSETX         0x5433
+#define TCSETXF                0x5434
+#define TCSETXW                0x5435
 
 #define FIONCLEX       0x5450
 #define FIOCLEX                0x5451
index 424acb48cd61baf681f7d71fb6b4ad56e1cfc3ee..2bdab21f0898dedee3ad1bf495b73b7ae0d3f997 100644 (file)
@@ -166,27 +166,6 @@ static inline int raw_irqs_disabled(void)
        return raw_irqs_disabled_flags(flags);
 }
 
-/*
- * makes the traced hardirq state match with the machine state
- *
- * should be a rarely used function, only in places where its
- * otherwise impossible to know the irq state, like in traps.
- */
-static inline void trace_hardirqs_fixup_flags(unsigned long flags)
-{
-       if (raw_irqs_disabled_flags(flags))
-               trace_hardirqs_off();
-       else
-               trace_hardirqs_on();
-}
-
-static inline void trace_hardirqs_fixup(void)
-{
-       unsigned long flags = __raw_local_save_flags();
-
-       trace_hardirqs_fixup_flags(flags);
-}
-
 #else
 
 #ifdef CONFIG_X86_64
index 5ec3ad3e825c4dadfcbcff6b6f9c880f6ec02c7a..fbbab66ee9dfb9c8385e2ff40f92e245b887f924 100644 (file)
@@ -27,10 +27,9 @@ extern void printk_address(unsigned long address, int reliable);
 extern void die(const char *, struct pt_regs *,long);
 extern int __must_check __die(const char *, struct pt_regs *, long);
 extern void show_registers(struct pt_regs *regs);
-extern void __show_registers(struct pt_regs *, int all);
 extern void show_trace(struct task_struct *t, struct pt_regs *regs,
                       unsigned long *sp, unsigned long bp);
-extern void __show_regs(struct pt_regs *regs);
+extern void __show_regs(struct pt_regs *regs, int all);
 extern void show_regs(struct pt_regs *regs);
 extern unsigned long oops_begin(void);
 extern void oops_end(unsigned long, struct pt_regs *, int signr);
index bd8407863c13127f1ed7ce1384fce4086e135022..8a0748d01036711c509e99d2d5121fbd81100380 100644 (file)
@@ -82,15 +82,6 @@ struct kprobe_ctlblk {
        struct prev_kprobe prev_kprobe;
 };
 
-/* trap3/1 are intr gates for kprobes.  So, restore the status of IF,
- * if necessary, before executing the original int3/1 (trap) handler.
- */
-static inline void restore_interrupts(struct pt_regs *regs)
-{
-       if (regs->flags & X86_EFLAGS_IF)
-               local_irq_enable();
-}
-
 extern int kprobe_fault_handler(struct pt_regs *regs, int trapnr);
 extern int kprobe_exceptions_notify(struct notifier_block *self,
                                    unsigned long val, void *data);
index de9ac3f5c4ce547c2a204cac41c4010da2839fe7..ff8778f26b84e3a9125b4a4f383b69ab649c5b20 100644 (file)
@@ -7,12 +7,6 @@
 
 #include <asm/mc146818rtc.h>
 
-static inline void clear_mem_error(unsigned char reason)
-{
-       reason = (reason & 0xf) | 4;
-       outb(reason, 0x61);
-}
-
 static inline unsigned char get_nmi_reason(void)
 {
        return inb(0x61);
index 48dc3e0c07d9a27b828ea614689a939e0baa581b..864f2005fc1d323f27bc853608ce74eefd32698e 100644 (file)
@@ -52,8 +52,6 @@ struct mod_arch_specific {};
 #define MODULE_PROC_FAMILY "EFFICEON "
 #elif defined CONFIG_MWINCHIPC6
 #define MODULE_PROC_FAMILY "WINCHIPC6 "
-#elif defined CONFIG_MWINCHIP2
-#define MODULE_PROC_FAMILY "WINCHIP2 "
 #elif defined CONFIG_MWINCHIP3D
 #define MODULE_PROC_FAMILY "WINCHIP3D "
 #elif defined CONFIG_MCYRIXIII
index d5e715f024dcc79d2818d78c2f651ac8d1b32807..a53f829a97c581c7b4a0d3cd77e4a0ea2cdf4ae3 100644 (file)
  */
 int do_nmi_callback(struct pt_regs *regs, int cpu);
 
-#ifdef CONFIG_X86_64
-extern void default_do_nmi(struct pt_regs *);
-#endif
-
 extern void die_nmi(char *str, struct pt_regs *regs, int do_panic);
 extern int check_nmi_watchdog(void);
 extern int nmi_watchdog_enabled;
index c91574776751396207f1aa2ce903e15a82239d47..d4f1d5791fc186f29a9a60d4fe182d80f05038e4 100644 (file)
@@ -179,6 +179,7 @@ static inline pteval_t native_pte_flags(pte_t pte)
 #endif /* CONFIG_PARAVIRT */
 
 #define __pa(x)                __phys_addr((unsigned long)(x))
+#define __pa_nodebug(x)        __phys_addr_nodebug((unsigned long)(x))
 /* __pa_symbol should be used for C visible symbols.
    This seems to be the official gcc blessed way to do such arithmetic. */
 #define __pa_symbol(x) __pa(__phys_reloc_hide((unsigned long)(x)))
@@ -188,9 +189,14 @@ static inline pteval_t native_pte_flags(pte_t pte)
 #define __boot_va(x)           __va(x)
 #define __boot_pa(x)           __pa(x)
 
+/*
+ * virt_to_page(kaddr) returns a valid pointer if and only if
+ * virt_addr_valid(kaddr) returns true.
+ */
 #define virt_to_page(kaddr)    pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
 #define pfn_to_kaddr(pfn)      __va((pfn) << PAGE_SHIFT)
-#define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
+extern bool __virt_addr_valid(unsigned long kaddr);
+#define virt_addr_valid(kaddr) __virt_addr_valid((unsigned long) (kaddr))
 
 #endif /* __ASSEMBLY__ */
 
index 9c5a737a9af9878ee128d15a90505afd6f733737..e8d80d1de237bd502ce1412862f71d17bb201d90 100644 (file)
 #endif
 #define THREAD_SIZE    (PAGE_SIZE << THREAD_ORDER)
 
+#define STACKFAULT_STACK 0
+#define DOUBLEFAULT_STACK 1
+#define NMI_STACK 0
+#define DEBUG_STACK 0
+#define MCE_STACK 0
+#define N_EXCEPTION_STACKS 1
 
 #ifdef CONFIG_X86_PAE
 /* 44=32+12, the limit we can fit into an unsigned long pfn */
@@ -73,11 +79,11 @@ typedef struct page *pgtable_t;
 #endif
 
 #ifndef __ASSEMBLY__
-#define __phys_addr_const(x)   ((x) - PAGE_OFFSET)
+#define __phys_addr_nodebug(x) ((x) - PAGE_OFFSET)
 #ifdef CONFIG_DEBUG_VIRTUAL
 extern unsigned long __phys_addr(unsigned long);
 #else
-#define __phys_addr(x)         ((x) - PAGE_OFFSET)
+#define __phys_addr(x)         __phys_addr_nodebug(x)
 #endif
 #define __phys_reloc_hide(x)   RELOC_HIDE((x), 0)
 
index ed932453ef26a3538ce3fd2c7670dfc78c18d9b9..182f9d4c570f5e9f33d3cd5b1b161a37d313fe36 100644 (file)
@@ -15,7 +15,7 @@
 #define _PAGE_BIT_PAT          7       /* on 4KB pages */
 #define _PAGE_BIT_GLOBAL       8       /* Global TLB entry PPro+ */
 #define _PAGE_BIT_UNUSED1      9       /* available for programmer */
-#define _PAGE_BIT_UNUSED2      10
+#define _PAGE_BIT_IOMAP                10      /* flag used to indicate IO mapping */
 #define _PAGE_BIT_UNUSED3      11
 #define _PAGE_BIT_PAT_LARGE    12      /* On 2MB or 1GB pages */
 #define _PAGE_BIT_SPECIAL      _PAGE_BIT_UNUSED1
@@ -32,7 +32,7 @@
 #define _PAGE_PSE      (_AT(pteval_t, 1) << _PAGE_BIT_PSE)
 #define _PAGE_GLOBAL   (_AT(pteval_t, 1) << _PAGE_BIT_GLOBAL)
 #define _PAGE_UNUSED1  (_AT(pteval_t, 1) << _PAGE_BIT_UNUSED1)
-#define _PAGE_UNUSED2  (_AT(pteval_t, 1) << _PAGE_BIT_UNUSED2)
+#define _PAGE_IOMAP    (_AT(pteval_t, 1) << _PAGE_BIT_IOMAP)
 #define _PAGE_UNUSED3  (_AT(pteval_t, 1) << _PAGE_BIT_UNUSED3)
 #define _PAGE_PAT      (_AT(pteval_t, 1) << _PAGE_BIT_PAT)
 #define _PAGE_PAT_LARGE (_AT(pteval_t, 1) << _PAGE_BIT_PAT_LARGE)
 #define __PAGE_KERNEL_LARGE_NOCACHE    (__PAGE_KERNEL | _PAGE_CACHE_UC | _PAGE_PSE)
 #define __PAGE_KERNEL_LARGE_EXEC       (__PAGE_KERNEL_EXEC | _PAGE_PSE)
 
+#define __PAGE_KERNEL_IO               (__PAGE_KERNEL | _PAGE_IOMAP)
+#define __PAGE_KERNEL_IO_NOCACHE       (__PAGE_KERNEL_NOCACHE | _PAGE_IOMAP)
+#define __PAGE_KERNEL_IO_UC_MINUS      (__PAGE_KERNEL_UC_MINUS | _PAGE_IOMAP)
+#define __PAGE_KERNEL_IO_WC            (__PAGE_KERNEL_WC | _PAGE_IOMAP)
+
 #define PAGE_KERNEL                    __pgprot(__PAGE_KERNEL)
 #define PAGE_KERNEL_RO                 __pgprot(__PAGE_KERNEL_RO)
 #define PAGE_KERNEL_EXEC               __pgprot(__PAGE_KERNEL_EXEC)
 #define PAGE_KERNEL_VSYSCALL           __pgprot(__PAGE_KERNEL_VSYSCALL)
 #define PAGE_KERNEL_VSYSCALL_NOCACHE   __pgprot(__PAGE_KERNEL_VSYSCALL_NOCACHE)
 
+#define PAGE_KERNEL_IO                 __pgprot(__PAGE_KERNEL_IO)
+#define PAGE_KERNEL_IO_NOCACHE         __pgprot(__PAGE_KERNEL_IO_NOCACHE)
+#define PAGE_KERNEL_IO_UC_MINUS                __pgprot(__PAGE_KERNEL_IO_UC_MINUS)
+#define PAGE_KERNEL_IO_WC              __pgprot(__PAGE_KERNEL_IO_WC)
+
 /*         xwr */
 #define __P000 PAGE_NONE
 #define __P001 PAGE_READONLY
@@ -196,7 +206,7 @@ static inline int pte_exec(pte_t pte)
 
 static inline int pte_special(pte_t pte)
 {
-       return pte_val(pte) & _PAGE_SPECIAL;
+       return pte_flags(pte) & _PAGE_SPECIAL;
 }
 
 static inline unsigned long pte_pfn(pte_t pte)
index ac578f11c1c563e03cb31bf3e1a61fdfe2288c34..a2025525a15ab20dca199a9e3acf95b2d1d7fcff 100644 (file)
@@ -174,12 +174,8 @@ extern unsigned long profile_pc(struct pt_regs *regs);
 
 extern unsigned long
 convert_ip_to_linear(struct task_struct *child, struct pt_regs *regs);
-
-#ifdef CONFIG_X86_32
 extern void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs,
                         int error_code, int si_code);
-#endif
-
 void signal_fault(struct pt_regs *regs, void __user *frame, char *where);
 
 extern long syscall_trace_enter(struct pt_regs *);
index ea5f0a8686f7539e32e92f801574454c9b3a6846..5d6e6945489152932b8e0f1216a035fc53e9fb33 100644 (file)
  * Matching rules for certain types of segments.
  */
 
-/* Matches only __KERNEL_CS, ignoring PnP / USER / APM segments */
-#define SEGMENT_IS_KERNEL_CODE(x) (((x) & 0xfc) == GDT_ENTRY_KERNEL_CS * 8)
-
-/* Matches __KERNEL_CS and __USER_CS (they must be 2 entries apart) */
-#define SEGMENT_IS_FLAT_CODE(x)  (((x) & 0xec) == GDT_ENTRY_KERNEL_CS * 8)
-
 /* Matches PNP_CS32 and PNP_CS16 (they must be consecutive) */
 #define SEGMENT_IS_PNP_CODE(x)   (((x) & 0xf4) == GDT_ENTRY_PNPBIOS_BASE * 8)
 
index 6df2615f9138728cfd29ea2ac46a0194c1fd1555..a6afc29f2dd9981e713a36d3ec14b507796415bf 100644 (file)
@@ -141,6 +141,8 @@ void play_dead_common(void);
 void native_send_call_func_ipi(cpumask_t mask);
 void native_send_call_func_single_ipi(int cpu);
 
+extern void prefill_possible_map(void);
+
 void smp_store_cpu_info(int id);
 #define cpu_physical_id(cpu)   per_cpu(x86_cpu_to_apicid, cpu)
 
@@ -149,15 +151,11 @@ static inline int num_booting_cpus(void)
 {
        return cpus_weight(cpu_callout_map);
 }
-#endif /* CONFIG_SMP */
-
-#if defined(CONFIG_SMP) && defined(CONFIG_HOTPLUG_CPU)
-extern void prefill_possible_map(void);
 #else
 static inline void prefill_possible_map(void)
 {
 }
-#endif
+#endif /* CONFIG_SMP */
 
 extern unsigned disabled_cpus __cpuinitdata;
 
index 3f005bc3aa5bb0e35c6421927f6ad999d8181a1f..ca5dc19dd461f95368b38fc9fb8c96bebd86d58d 100644 (file)
@@ -1,63 +1,12 @@
 #ifndef ASM_X86__STATFS_H
 #define ASM_X86__STATFS_H
 
-#ifdef __i386__
-#include <asm-generic/statfs.h>
-#else
-
-#ifndef __KERNEL_STRICT_NAMES
-
-#include <linux/types.h>
-
-typedef __kernel_fsid_t        fsid_t;
-
-#endif
-
 /*
- * This is ugly -- we're already 64-bit clean, so just duplicate the
- * definitions.
+ * We need compat_statfs64 to be packed, because the i386 ABI won't
+ * add padding at the end to bring it to a multiple of 8 bytes, but
+ * the x86_64 ABI will.
  */
-struct statfs {
-       long f_type;
-       long f_bsize;
-       long f_blocks;
-       long f_bfree;
-       long f_bavail;
-       long f_files;
-       long f_ffree;
-       __kernel_fsid_t f_fsid;
-       long f_namelen;
-       long f_frsize;
-       long f_spare[5];
-};
-
-struct statfs64 {
-       long f_type;
-       long f_bsize;
-       long f_blocks;
-       long f_bfree;
-       long f_bavail;
-       long f_files;
-       long f_ffree;
-       __kernel_fsid_t f_fsid;
-       long f_namelen;
-       long f_frsize;
-       long f_spare[5];
-};
+#define ARCH_PACK_COMPAT_STATFS64 __attribute__((packed,aligned(4)))
 
-struct compat_statfs64 {
-       __u32 f_type;
-       __u32 f_bsize;
-       __u64 f_blocks;
-       __u64 f_bfree;
-       __u64 f_bavail;
-       __u64 f_files;
-       __u64 f_ffree;
-       __kernel_fsid_t f_fsid;
-       __u32 f_namelen;
-       __u32 f_frsize;
-       __u32 f_spare[5];
-} __attribute__((packed));
-
-#endif /* !__i386__ */
+#include <asm-generic/statfs.h>
 #endif /* ASM_X86__STATFS_H */
index 34505dd7b24de4ad67b968f93b3fc24156700206..b20c894660f95ee1d056d86a238e2bb116cb673c 100644 (file)
@@ -64,7 +64,10 @@ do {                                                                 \
                                                                        \
                       /* regparm parameters for __switch_to(): */      \
                       [prev]     "a" (prev),                           \
-                      [next]     "d" (next));                          \
+                      [next]     "d" (next)                            \
+                                                                       \
+                    : /* reloaded segment registers */                 \
+                       "memory");                                      \
 } while (0)
 
 /*
index 7a692baa51ae1548cf255c514ec4521a77a815b3..6c3dc2c65751fbb832d8c7fa26dc318c401c80b2 100644 (file)
@@ -3,7 +3,12 @@
 
 #include <asm/debugreg.h>
 
-/* Common in X86_32 and X86_64 */
+#ifdef CONFIG_X86_32
+#define dotraplinkage
+#else
+#define dotraplinkage asmlinkage
+#endif
+
 asmlinkage void divide_error(void);
 asmlinkage void debug(void);
 asmlinkage void nmi(void);
@@ -12,31 +17,47 @@ asmlinkage void overflow(void);
 asmlinkage void bounds(void);
 asmlinkage void invalid_op(void);
 asmlinkage void device_not_available(void);
+#ifdef CONFIG_X86_64
+asmlinkage void double_fault(void);
+#endif
 asmlinkage void coprocessor_segment_overrun(void);
 asmlinkage void invalid_TSS(void);
 asmlinkage void segment_not_present(void);
 asmlinkage void stack_segment(void);
 asmlinkage void general_protection(void);
 asmlinkage void page_fault(void);
+asmlinkage void spurious_interrupt_bug(void);
 asmlinkage void coprocessor_error(void);
-asmlinkage void simd_coprocessor_error(void);
 asmlinkage void alignment_check(void);
-asmlinkage void spurious_interrupt_bug(void);
 #ifdef CONFIG_X86_MCE
 asmlinkage void machine_check(void);
 #endif /* CONFIG_X86_MCE */
+asmlinkage void simd_coprocessor_error(void);
 
-void do_divide_error(struct pt_regs *, long);
-void do_overflow(struct pt_regs *, long);
-void do_bounds(struct pt_regs *, long);
-void do_coprocessor_segment_overrun(struct pt_regs *, long);
-void do_invalid_TSS(struct pt_regs *, long);
-void do_segment_not_present(struct pt_regs *, long);
-void do_stack_segment(struct pt_regs *, long);
-void do_alignment_check(struct pt_regs *, long);
-void do_invalid_op(struct pt_regs *, long);
-void do_general_protection(struct pt_regs *, long);
-void do_nmi(struct pt_regs *, long);
+dotraplinkage void do_divide_error(struct pt_regs *, long);
+dotraplinkage void do_debug(struct pt_regs *, long);
+dotraplinkage void do_nmi(struct pt_regs *, long);
+dotraplinkage void do_int3(struct pt_regs *, long);
+dotraplinkage void do_overflow(struct pt_regs *, long);
+dotraplinkage void do_bounds(struct pt_regs *, long);
+dotraplinkage void do_invalid_op(struct pt_regs *, long);
+dotraplinkage void do_device_not_available(struct pt_regs *, long);
+dotraplinkage void do_coprocessor_segment_overrun(struct pt_regs *, long);
+dotraplinkage void do_invalid_TSS(struct pt_regs *, long);
+dotraplinkage void do_segment_not_present(struct pt_regs *, long);
+dotraplinkage void do_stack_segment(struct pt_regs *, long);
+dotraplinkage void do_general_protection(struct pt_regs *, long);
+dotraplinkage void do_page_fault(struct pt_regs *, unsigned long);
+dotraplinkage void do_spurious_interrupt_bug(struct pt_regs *, long);
+dotraplinkage void do_coprocessor_error(struct pt_regs *, long);
+dotraplinkage void do_alignment_check(struct pt_regs *, long);
+#ifdef CONFIG_X86_MCE
+dotraplinkage void do_machine_check(struct pt_regs *, long);
+#endif
+dotraplinkage void do_simd_coprocessor_error(struct pt_regs *, long);
+#ifdef CONFIG_X86_32
+dotraplinkage void do_iret_error(struct pt_regs *, long);
+#endif
 
 static inline int get_si_code(unsigned long condition)
 {
@@ -52,31 +73,9 @@ extern int panic_on_unrecovered_nmi;
 extern int kstack_depth_to_print;
 
 #ifdef CONFIG_X86_32
-
-void do_iret_error(struct pt_regs *, long);
-void do_int3(struct pt_regs *, long);
-void do_debug(struct pt_regs *, long);
 void math_error(void __user *);
-void do_coprocessor_error(struct pt_regs *, long);
-void do_simd_coprocessor_error(struct pt_regs *, long);
-void do_spurious_interrupt_bug(struct pt_regs *, long);
 unsigned long patch_espfix_desc(unsigned long, unsigned long);
 asmlinkage void math_emulate(long);
+#endif
 
-void do_page_fault(struct pt_regs *regs, unsigned long error_code);
-
-#else /* CONFIG_X86_32 */
-
-asmlinkage void double_fault(void);
-
-asmlinkage void do_int3(struct pt_regs *, long);
-asmlinkage void do_stack_segment(struct pt_regs *, long);
-asmlinkage void do_debug(struct pt_regs *, unsigned long);
-asmlinkage void do_coprocessor_error(struct pt_regs *);
-asmlinkage void do_simd_coprocessor_error(struct pt_regs *);
-asmlinkage void do_spurious_interrupt_bug(struct pt_regs *);
-
-asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code);
-
-#endif /* CONFIG_X86_32 */
 #endif /* ASM_X86__TRAPS_H */
diff --git a/include/asm-xtensa/a.out.h b/include/asm-xtensa/a.out.h
deleted file mode 100644 (file)
index fdf1370..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * include/asm-xtensa/a.out.h
- *
- * Dummy a.out file. Xtensa does not support the a.out format, but the kernel
- * seems to depend on it.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2001 - 2005 Tensilica Inc.
- */
-
-#ifndef _XTENSA_A_OUT_H
-#define _XTENSA_A_OUT_H
-
-struct exec
-{
-  unsigned long a_info;
-  unsigned a_text;
-  unsigned a_data;
-  unsigned a_bss;
-  unsigned a_syms;
-  unsigned a_entry;
-  unsigned a_trsize;
-  unsigned a_drsize;
-};
-
-#endif /* _XTENSA_A_OUT_H */
index 154769cad3f31c7207b3113ec5e00753a4684ee2..5ce0e5fd712e0fe67d0e05b455fffbb85c16fb7c 100644 (file)
 
 #ifdef CONFIG_UNIX98_PTYS
 
-int devpts_new_index(void);
-void devpts_kill_index(int idx);
-int devpts_pty_new(struct tty_struct *tty);      /* mknod in devpts */
-struct tty_struct *devpts_get_tty(int number);  /* get tty structure */
-void devpts_pty_kill(int number);               /* unlink */
+int devpts_new_index(struct inode *ptmx_inode);
+void devpts_kill_index(struct inode *ptmx_inode, int idx);
+/* mknod in devpts */
+int devpts_pty_new(struct inode *ptmx_inode, struct tty_struct *tty);
+/* get tty structure */
+struct tty_struct *devpts_get_tty(struct inode *pts_inode, int number);
+/* unlink */
+void devpts_pty_kill(struct tty_struct *tty);
 
 #else
 
 /* Dummy stubs in the no-pty case */
-static inline int devpts_new_index(void) { return -EINVAL; }
-static inline void devpts_kill_index(int idx) { }
-static inline int devpts_pty_new(struct tty_struct *tty) { return -EINVAL; }
-static inline struct tty_struct *devpts_get_tty(int number) { return NULL; }
-static inline void devpts_pty_kill(int number) { }
+static inline int devpts_new_index(struct inode *ptmx_inode) { return -EINVAL; }
+static inline void devpts_kill_index(struct inode *ptmx_inode, int idx) { }
+static inline int devpts_pty_new(struct inode *ptmx_inode,
+                               struct tty_struct *tty)
+{
+       return -EINVAL;
+}
+static inline struct tty_struct *devpts_get_tty(struct inode *pts_inode,
+               int number)
+{
+       return NULL;
+}
+static inline void devpts_pty_kill(struct tty_struct *tty) { }
 
 #endif
 
index 2a063b64133fcd23307e57b6b396fa935eb7c808..e5084eb5943a5f35fc82680e3a83103f19a46019 100644 (file)
@@ -2,29 +2,9 @@
 #define __DMI_H__
 
 #include <linux/list.h>
+#include <linux/mod_devicetable.h>
 
-enum dmi_field {
-       DMI_NONE,
-       DMI_BIOS_VENDOR,
-       DMI_BIOS_VERSION,
-       DMI_BIOS_DATE,
-       DMI_SYS_VENDOR,
-       DMI_PRODUCT_NAME,
-       DMI_PRODUCT_VERSION,
-       DMI_PRODUCT_SERIAL,
-       DMI_PRODUCT_UUID,
-       DMI_BOARD_VENDOR,
-       DMI_BOARD_NAME,
-       DMI_BOARD_VERSION,
-       DMI_BOARD_SERIAL,
-       DMI_BOARD_ASSET_TAG,
-       DMI_CHASSIS_VENDOR,
-       DMI_CHASSIS_TYPE,
-       DMI_CHASSIS_VERSION,
-       DMI_CHASSIS_SERIAL,
-       DMI_CHASSIS_ASSET_TAG,
-       DMI_STRING_MAX,
-};
+/* enum dmi_field is in mod_devicetable.h */
 
 enum dmi_device_type {
        DMI_DEV_TYPE_ANY = 0,
@@ -48,23 +28,6 @@ struct dmi_header {
        u16 handle;
 };
 
-/*
- *     DMI callbacks for problem boards
- */
-struct dmi_strmatch {
-       u8 slot;
-       char *substr;
-};
-
-struct dmi_system_id {
-       int (*callback)(const struct dmi_system_id *);
-       const char *ident;
-       struct dmi_strmatch matches[4];
-       void *driver_data;
-};
-
-#define DMI_MATCH(a, b)        { a, b }
-
 struct dmi_device {
        struct list_head list;
        int type;
index 2dc29ce6c8e482da3a640290d517da90a525e422..79f63a27bcef0817752cc5c27762ae81a2fb9092 100644 (file)
@@ -37,6 +37,7 @@ struct hpet {
 #define        hpet_compare    _u1._hpet_compare
 
 #define        HPET_MAX_TIMERS (32)
+#define        HPET_MAX_IRQ    (32)
 
 /*
  * HPET general capabilities register
@@ -64,7 +65,7 @@ struct hpet {
  */
 
 #define        Tn_INT_ROUTE_CAP_MASK           (0xffffffff00000000ULL)
-#define        Tn_INI_ROUTE_CAP_SHIFT          (32UL)
+#define        Tn_INT_ROUTE_CAP_SHIFT          (32UL)
 #define        Tn_FSB_INT_DELCAP_MASK          (0x8000UL)
 #define        Tn_FSB_INT_DELCAP_SHIFT         (15)
 #define        Tn_FSB_EN_CNF_MASK              (0x4000UL)
@@ -91,23 +92,14 @@ struct hpet {
  * exported interfaces
  */
 
-struct hpet_task {
-       void (*ht_func) (void *);
-       void *ht_data;
-       void *ht_opaque;
-};
-
 struct hpet_data {
        unsigned long hd_phys_address;
        void __iomem *hd_address;
        unsigned short hd_nirqs;
-       unsigned short hd_flags;
        unsigned int hd_state;  /* timer allocated */
        unsigned int hd_irq[HPET_MAX_TIMERS];
 };
 
-#define        HPET_DATA_PLATFORM      0x0001  /* platform call to hpet_alloc */
-
 static inline void hpet_reserve_timer(struct hpet_data *hd, int timer)
 {
        hd->hd_state |= (1 << timer);
@@ -125,7 +117,7 @@ struct hpet_info {
        unsigned short hi_timer;
 };
 
-#define        HPET_INFO_PERIODIC      0x0001  /* timer is periodic */
+#define HPET_INFO_PERIODIC     0x0010  /* periodic-capable comparator */
 
 #define        HPET_IE_ON      _IO('h', 0x01)  /* interrupt on */
 #define        HPET_IE_OFF     _IO('h', 0x02)  /* interrupt off */
index 1fa0c2ce4dec09456f5cb6c2480f6be5e5eb908a..f7f3fdddbef0b5f4f599cd506c524e4c9bf0b911 100644 (file)
@@ -6,6 +6,10 @@
 #define AFS_SUPER_MAGIC                0x5346414F
 #define AUTOFS_SUPER_MAGIC     0x0187
 #define CODA_SUPER_MAGIC       0x73757245
+#define DEBUGFS_MAGIC          0x64626720
+#define SYSFS_MAGIC            0x62656572
+#define SECURITYFS_MAGIC       0x73636673
+#define TMPFS_MAGIC            0x01021994
 #define EFS_SUPER_MAGIC                0x414A53
 #define EXT2_SUPER_MAGIC       0xEF53
 #define EXT3_SUPER_MAGIC       0xEF53
index c4db5827963d98a5624ec1c8fb637ad959903a75..3481a7d5bc0a0e143e4d78814e28628804b1fa13 100644 (file)
@@ -388,5 +388,52 @@ struct i2c_device_id {
                        __attribute__((aligned(sizeof(kernel_ulong_t))));
 };
 
+/* dmi */
+enum dmi_field {
+       DMI_NONE,
+       DMI_BIOS_VENDOR,
+       DMI_BIOS_VERSION,
+       DMI_BIOS_DATE,
+       DMI_SYS_VENDOR,
+       DMI_PRODUCT_NAME,
+       DMI_PRODUCT_VERSION,
+       DMI_PRODUCT_SERIAL,
+       DMI_PRODUCT_UUID,
+       DMI_BOARD_VENDOR,
+       DMI_BOARD_NAME,
+       DMI_BOARD_VERSION,
+       DMI_BOARD_SERIAL,
+       DMI_BOARD_ASSET_TAG,
+       DMI_CHASSIS_VENDOR,
+       DMI_CHASSIS_TYPE,
+       DMI_CHASSIS_VERSION,
+       DMI_CHASSIS_SERIAL,
+       DMI_CHASSIS_ASSET_TAG,
+       DMI_STRING_MAX,
+};
+
+struct dmi_strmatch {
+       unsigned char slot;
+       char substr[79];
+};
+
+#ifndef __KERNEL__
+struct dmi_system_id {
+       kernel_ulong_t callback;
+       kernel_ulong_t ident;
+       struct dmi_strmatch matches[4];
+       kernel_ulong_t driver_data
+                       __attribute__((aligned(sizeof(kernel_ulong_t))));
+};
+#else
+struct dmi_system_id {
+       int (*callback)(const struct dmi_system_id *);
+       const char *ident;
+       struct dmi_strmatch matches[4];
+       void *driver_data;
+};
+#endif
+
+#define DMI_MATCH(a, b)        { a, b }
 
 #endif /* LINUX_MOD_DEVICETABLE_H */
index 041bb31100f48fd780b9505cf21842be36cdb68f..bcb8f725427c4868a6f4e6461a1ee720ed8b793c 100644 (file)
@@ -36,6 +36,8 @@
 #define XEN_ENTER_SWITCH_CODE          10
 #define SPU_PROFILING_CODE             11
 #define SPU_CTX_SWITCH_CODE            12
+#define IBS_FETCH_CODE                 13
+#define IBS_OP_CODE                    14
 
 struct super_block;
 struct dentry;
index f63b5455801caca2a66fa4d9b2618a74f66a6859..1176f1f177e298533b80e571a14513ab60c9cfbb 100644 (file)
 #define PCI_DEVICE_ID_MARVELL_GT64260  0x6430
 #define PCI_DEVICE_ID_MARVELL_MV64360  0x6460
 #define PCI_DEVICE_ID_MARVELL_MV64460  0x6480
-#define PCI_DEVICE_ID_MARVELL_CAFE_SD  0x4101
+#define PCI_DEVICE_ID_MARVELL_88ALP01_NAND     0x4100
+#define PCI_DEVICE_ID_MARVELL_88ALP01_SD       0x4101
+#define PCI_DEVICE_ID_MARVELL_88ALP01_CCIC     0x4102
 
 #define PCI_VENDOR_ID_V3               0x11b0
 #define PCI_DEVICE_ID_V3_V960          0x0001
index deb714314fb169de39bf195921c01b2a7e8085a6..1ea8d9265bf67c5bc52d1a43b2557d9ae661c2df 100644 (file)
@@ -173,6 +173,22 @@ struct serial_icounter_struct {
        int reserved[9];
 };
 
+/*
+ * Serial interface for controlling RS485 settings on chips with suitable
+ * support. Set with TIOCSRS485 and get with TIOCGRS485 if supported by your
+ * platform. The set function returns the new state, with any unsupported bits
+ * reverted appropriately.
+ */
+
+struct serial_rs485 {
+       __u32   flags;                  /* RS485 feature flags */
+#define SER_RS485_ENABLED              (1 << 0)
+#define SER_RS485_RTS_ON_SEND          (1 << 1)
+#define SER_RS485_RTS_AFTER_SEND       (1 << 2)
+       __u32   delay_rts_before_send;  /* Milliseconds */
+       __u32   padding[6];             /* Memory is cheap, new structs
+                                          are a royal PITA .. */
+};
 
 #ifdef __KERNEL__
 #include <linux/compiler.h>
index 3b2f6c04855e73d0ea300803c13970729e9b2989..e27f216361fc1511f6fc6b52d7570536af95a9e6 100644 (file)
@@ -241,7 +241,7 @@ typedef unsigned int __bitwise__ upf_t;
 
 struct uart_port {
        spinlock_t              lock;                   /* port lock */
-       unsigned int            iobase;                 /* in/out[bwl] */
+       unsigned long           iobase;                 /* in/out[bwl] */
        unsigned char __iomem   *membase;               /* read/write[bwl] */
        unsigned int            irq;                    /* irq number */
        unsigned int            uartclk;                /* base uart clock */
index 478662889f487db6fb1b8f6abba1bd781831a445..2acd0c1f8a2a305c8c7fc23895a6cba3cdd35ea8 100644 (file)
@@ -4,4 +4,19 @@
 #include <linux/types.h>
 #include <asm/termios.h>
 
+#define NFF    5
+
+struct termiox
+{
+       __u16   x_hflag;
+       __u16   x_cflag;
+       __u16   x_rflag[NFF];
+       __u16   x_sflag;
+};
+
+#define        RTSXOFF         0x0001          /* RTS flow control on input */
+#define        CTSXON          0x0002          /* CTS flow control on output */
+#define        DTRXOFF         0x0004          /* DTR flow control on input */
+#define DSRXON         0x0008          /* DCD flow control on output */
+
 #endif
index 0cbec74ec0865af37673d58cbd435d7c39475279..3b8121d4e36ff90aff5c8f7fa9fe3865be0baacc 100644 (file)
@@ -23,7 +23,7 @@
  */
 #define NR_UNIX98_PTY_DEFAULT  4096      /* Default maximum for Unix98 ptys */
 #define NR_UNIX98_PTY_MAX      (1 << MINORBITS) /* Absolute limit */
-#define NR_LDISCS              18
+#define NR_LDISCS              19
 
 /* line disciplines */
 #define N_TTY          0
@@ -45,6 +45,7 @@
 #define N_HCI          15      /* Bluetooth HCI UART */
 #define N_GIGASET_M101 16      /* Siemens Gigaset M101 serial DECT adapter */
 #define N_SLCAN                17      /* Serial / USB serial CAN Adaptors */
+#define N_PPS          18      /* Pulse per Second */
 
 /*
  * This character is the same as _POSIX_VDISABLE: it cannot be used as
@@ -181,6 +182,7 @@ struct signal_struct;
 
 struct tty_port {
        struct tty_struct       *tty;           /* Back pointer */
+       spinlock_t              lock;           /* Lock protecting tty field */
        int                     blocked_open;   /* Waiting to open */
        int                     count;          /* Usage count */
        wait_queue_head_t       open_wait;      /* Open waiters */
@@ -208,6 +210,7 @@ struct tty_operations;
 
 struct tty_struct {
        int     magic;
+       struct kref kref;
        struct tty_driver *driver;
        const struct tty_operations *ops;
        int index;
@@ -217,6 +220,7 @@ struct tty_struct {
        spinlock_t ctrl_lock;
        /* Termios values are protected by the termios mutex */
        struct ktermios *termios, *termios_locked;
+       struct termiox *termiox;        /* May be NULL for unsupported */
        char name[64];
        struct pid *pgrp;               /* Protected by ctrl lock */
        struct pid *session;
@@ -310,6 +314,25 @@ extern int kmsg_redirect;
 extern void console_init(void);
 extern int vcs_init(void);
 
+extern struct class *tty_class;
+
+/**
+ *     tty_kref_get            -       get a tty reference
+ *     @tty: tty device
+ *
+ *     Return a new reference to a tty object. The caller must hold
+ *     sufficient locks/counts to ensure that their existing reference cannot
+ *     go away
+ */
+
+extern inline struct tty_struct *tty_kref_get(struct tty_struct *tty)
+{
+       if (tty)
+               kref_get(&tty->kref);
+       return tty;
+}
+extern void tty_kref_put(struct tty_struct *tty);
+
 extern int tty_paranoia_check(struct tty_struct *tty, struct inode *inode,
                              const char *routine);
 extern char *tty_name(struct tty_struct *tty, char *buf);
@@ -333,13 +356,15 @@ extern void tty_throttle(struct tty_struct *tty);
 extern void tty_unthrottle(struct tty_struct *tty);
 extern int tty_do_resize(struct tty_struct *tty, struct tty_struct *real_tty,
                                                struct winsize *ws);
-
+extern void tty_shutdown(struct tty_struct *tty);
+extern void tty_free_termios(struct tty_struct *tty);
 extern int is_current_pgrp_orphaned(void);
 extern struct pid *tty_get_pgrp(struct tty_struct *tty);
 extern int is_ignored(int sig);
 extern int tty_signal(int sig, struct tty_struct *tty);
 extern void tty_hangup(struct tty_struct *tty);
 extern void tty_vhangup(struct tty_struct *tty);
+extern void tty_vhangup_self(void);
 extern void tty_unhangup(struct file *filp);
 extern int tty_hung_up_p(struct file *filp);
 extern void do_SAK(struct tty_struct *tty);
@@ -347,6 +372,9 @@ extern void __do_SAK(struct tty_struct *tty);
 extern void disassociate_ctty(int priv);
 extern void no_tty(void);
 extern void tty_flip_buffer_push(struct tty_struct *tty);
+extern void tty_buffer_free_all(struct tty_struct *tty);
+extern void tty_buffer_flush(struct tty_struct *tty);
+extern void tty_buffer_init(struct tty_struct *tty);
 extern speed_t tty_get_baud_rate(struct tty_struct *tty);
 extern speed_t tty_termios_baud_rate(struct ktermios *termios);
 extern speed_t tty_termios_input_baud_rate(struct ktermios *termios);
@@ -372,6 +400,15 @@ extern int tty_perform_flush(struct tty_struct *tty, unsigned long arg);
 extern dev_t tty_devnum(struct tty_struct *tty);
 extern void proc_clear_tty(struct task_struct *p);
 extern struct tty_struct *get_current_tty(void);
+extern void tty_default_fops(struct file_operations *fops);
+extern struct tty_struct *alloc_tty_struct(void);
+extern void free_tty_struct(struct tty_struct *tty);
+extern void initialize_tty_struct(struct tty_struct *tty,
+               struct tty_driver *driver, int idx);
+extern struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx,
+                                                               int first_ok);
+extern void tty_release_dev(struct file *filp);
+extern int tty_init_termios(struct tty_struct *tty);
 
 extern struct mutex tty_mutex;
 
@@ -382,6 +419,8 @@ extern int tty_write_lock(struct tty_struct *tty, int ndelay);
 extern void tty_port_init(struct tty_port *port);
 extern int tty_port_alloc_xmit_buf(struct tty_port *port);
 extern void tty_port_free_xmit_buf(struct tty_port *port);
+extern struct tty_struct *tty_port_tty_get(struct tty_port *port);
+extern void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty);
 
 extern int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc);
 extern int tty_unregister_ldisc(int disc);
@@ -427,7 +466,7 @@ static inline void tty_audit_push_task(struct task_struct *tsk,
 #endif
 
 /* tty_ioctl.c */
-extern int n_tty_ioctl(struct tty_struct *tty, struct file *file,
+extern int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file,
                       unsigned int cmd, unsigned long arg);
 
 /* serial.c */
index 16d27944c3211af2f954fa6fff4950d3c3591812..78416b901589cd08cb1ea1410e1ac61986c2f4e0 100644 (file)
@@ -7,6 +7,28 @@
  * defined; unless noted otherwise, they are optional, and can be
  * filled in with a null pointer.
  *
+ * struct tty_struct * (*lookup)(struct tty_driver *self, int idx)
+ *
+ *     Return the tty device corresponding to idx, NULL if there is not
+ *     one currently in use and an ERR_PTR value on error. Called under
+ *     tty_mutex (for now!)
+ *
+ *     Optional method. Default behaviour is to use the ttys array
+ *
+ * int (*install)(struct tty_driver *self, struct tty_struct *tty)
+ *
+ *     Install a new tty into the tty driver internal tables. Used in
+ *     conjunction with lookup and remove methods.
+ *
+ *     Optional method. Default behaviour is to use the ttys array
+ *
+ * void (*remove)(struct tty_driver *self, struct tty_struct *tty)
+ *
+ *     Remove a closed tty from the tty driver internal tables. Used in
+ *     conjunction with lookup and remove methods.
+ *
+ *     Optional method. Default behaviour is to use the ttys array
+ *
  * int  (*open)(struct tty_struct * tty, struct file * filp);
  *
  *     This routine is called when a particular tty device is opened.
  *
  *     Required method.
  *
+ * void (*shutdown)(struct tty_struct * tty);
+ *
+ *     This routine is called when a particular tty device is closed for
+ *     the last time freeing up the resources.
+ *
  * int (*write)(struct tty_struct * tty,
  *              const unsigned char *buf, int count);
  *
  *     not force errors here if they are not resizable objects (eg a serial
  *     line). See tty_do_resize() if you need to wrap the standard method
  *     in your own logic - the usual case.
+ *
+ * void (*set_termiox)(struct tty_struct *tty, struct termiox *new);
+ *
+ *     Called when the device receives a termiox based ioctl. Passes down
+ *     the requested data from user space. This method will not be invoked
+ *     unless the tty also has a valid tty->termiox pointer.
+ *
+ *     Optional: Called under the termios lock
  */
 
 #include <linux/fs.h>
@@ -190,8 +225,13 @@ struct tty_struct;
 struct tty_driver;
 
 struct tty_operations {
+       struct tty_struct * (*lookup)(struct tty_driver *driver,
+                       struct inode *inode, int idx);
+       int  (*install)(struct tty_driver *driver, struct tty_struct *tty);
+       void (*remove)(struct tty_driver *driver, struct tty_struct *tty);
        int  (*open)(struct tty_struct * tty, struct file * filp);
        void (*close)(struct tty_struct * tty, struct file * filp);
+       void (*shutdown)(struct tty_struct *tty);
        int  (*write)(struct tty_struct * tty,
                      const unsigned char *buf, int count);
        int  (*put_char)(struct tty_struct *tty, unsigned char ch);
@@ -220,6 +260,7 @@ struct tty_operations {
                        unsigned int set, unsigned int clear);
        int (*resize)(struct tty_struct *tty, struct tty_struct *real_tty,
                                struct winsize *ws);
+       int (*set_termiox)(struct tty_struct *tty, struct termiox *tnew);
 #ifdef CONFIG_CONSOLE_POLL
        int (*poll_init)(struct tty_driver *driver, int line, char *options);
        int (*poll_get_char)(struct tty_driver *driver, int line);
@@ -229,6 +270,7 @@ struct tty_operations {
 
 struct tty_driver {
        int     magic;          /* magic number for this structure */
+       struct kref kref;       /* Reference management */
        struct cdev cdev;
        struct module   *owner;
        const char      *driver_name;
@@ -242,7 +284,6 @@ struct tty_driver {
        short   subtype;        /* subtype of tty driver */
        struct ktermios init_termios; /* Initial termios */
        int     flags;          /* tty driver flags */
-       int     refcount;       /* for loadable tty drivers */
        struct proc_dir_entry *proc_entry; /* /proc fs entry */
        struct tty_driver *other; /* only used for the PTY driver */
 
@@ -264,12 +305,19 @@ struct tty_driver {
 
 extern struct list_head tty_drivers;
 
-struct tty_driver *alloc_tty_driver(int lines);
-void put_tty_driver(struct tty_driver *driver);
-void tty_set_operations(struct tty_driver *driver,
+extern struct tty_driver *alloc_tty_driver(int lines);
+extern void put_tty_driver(struct tty_driver *driver);
+extern void tty_set_operations(struct tty_driver *driver,
                        const struct tty_operations *op);
 extern struct tty_driver *tty_find_polling_driver(char *name, int *line);
 
+extern void tty_driver_kref_put(struct tty_driver *driver);
+extern inline struct tty_driver *tty_driver_kref_get(struct tty_driver *d)
+{
+       kref_get(&d->kref);
+       return d;
+}
+
 /* tty driver magic number */
 #define TTY_DRIVER_MAGIC               0x5402
 
index 1cbd0a7db4e6b73c72084c346451573b0ea2e1a8..2f1113467f707b5b9e03a3d6243eb2beda5f1abc 100644 (file)
@@ -96,7 +96,7 @@ void change_console(struct vc_data *new_vc);
 void reset_vc(struct vc_data *vc);
 extern int unbind_con_driver(const struct consw *csw, int first, int last,
                             int deflt);
-int vty_init(void);
+int vty_init(const struct file_operations *console_fops);
 
 /*
  * vc_screen.c shares this temporary buffer with the console write code so that
index a6bb94530cfddfbd0e8d3bd10880fdfcd8c996b5..9909774eb998d973532d629a90d9017f11eacd90 100644 (file)
 #include <linux/net.h>
 #include <linux/skbuff.h>
 #include <net/netlabel.h>
+#include <asm/atomic.h>
 
 /* known doi values */
 #define CIPSO_V4_DOI_UNKNOWN          0x00000000
 
-/* tag types */
+/* standard tag types */
 #define CIPSO_V4_TAG_INVALID          0
 #define CIPSO_V4_TAG_RBITMAP          1
 #define CIPSO_V4_TAG_ENUM             2
 #define CIPSO_V4_TAG_PBITMAP          6
 #define CIPSO_V4_TAG_FREEFORM         7
 
+/* non-standard tag types (tags > 127) */
+#define CIPSO_V4_TAG_LOCAL            128
+
 /* doi mapping types */
 #define CIPSO_V4_MAP_UNKNOWN          0
-#define CIPSO_V4_MAP_STD              1
+#define CIPSO_V4_MAP_TRANS            1
 #define CIPSO_V4_MAP_PASS             2
+#define CIPSO_V4_MAP_LOCAL            3
 
 /* limits */
 #define CIPSO_V4_MAX_REM_LVLS         255
@@ -79,10 +84,9 @@ struct cipso_v4_doi {
        } map;
        u8 tags[CIPSO_V4_TAG_MAXCNT];
 
-       u32 valid;
+       atomic_t refcount;
        struct list_head list;
        struct rcu_head rcu;
-       struct list_head dom_list;
 };
 
 /* Standard CIPSO mapping table */
@@ -128,25 +132,26 @@ extern int cipso_v4_rbm_strictvalid;
 
 #ifdef CONFIG_NETLABEL
 int cipso_v4_doi_add(struct cipso_v4_doi *doi_def);
-int cipso_v4_doi_remove(u32 doi,
-                       struct netlbl_audit *audit_info,
-                       void (*callback) (struct rcu_head * head));
+void cipso_v4_doi_free(struct cipso_v4_doi *doi_def);
+int cipso_v4_doi_remove(u32 doi, struct netlbl_audit *audit_info);
 struct cipso_v4_doi *cipso_v4_doi_getdef(u32 doi);
+void cipso_v4_doi_putdef(struct cipso_v4_doi *doi_def);
 int cipso_v4_doi_walk(u32 *skip_cnt,
                     int (*callback) (struct cipso_v4_doi *doi_def, void *arg),
                     void *cb_arg);
-int cipso_v4_doi_domhsh_add(struct cipso_v4_doi *doi_def, const char *domain);
-int cipso_v4_doi_domhsh_remove(struct cipso_v4_doi *doi_def,
-                              const char *domain);
 #else
 static inline int cipso_v4_doi_add(struct cipso_v4_doi *doi_def)
 {
        return -ENOSYS;
 }
 
+static inline void cipso_v4_doi_free(struct cipso_v4_doi *doi_def)
+{
+       return;
+}
+
 static inline int cipso_v4_doi_remove(u32 doi,
-                                   struct netlbl_audit *audit_info,
-                                   void (*callback) (struct rcu_head * head))
+                                     struct netlbl_audit *audit_info)
 {
        return 0;
 }
@@ -206,10 +211,15 @@ void cipso_v4_error(struct sk_buff *skb, int error, u32 gateway);
 int cipso_v4_sock_setattr(struct sock *sk,
                          const struct cipso_v4_doi *doi_def,
                          const struct netlbl_lsm_secattr *secattr);
+void cipso_v4_sock_delattr(struct sock *sk);
 int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr);
+int cipso_v4_skbuff_setattr(struct sk_buff *skb,
+                           const struct cipso_v4_doi *doi_def,
+                           const struct netlbl_lsm_secattr *secattr);
+int cipso_v4_skbuff_delattr(struct sk_buff *skb);
 int cipso_v4_skbuff_getattr(const struct sk_buff *skb,
                            struct netlbl_lsm_secattr *secattr);
-int cipso_v4_validate(unsigned char **option);
+int cipso_v4_validate(const struct sk_buff *skb, unsigned char **option);
 #else
 static inline void cipso_v4_error(struct sk_buff *skb,
                                  int error,
@@ -225,19 +235,36 @@ static inline int cipso_v4_sock_setattr(struct sock *sk,
        return -ENOSYS;
 }
 
+static inline void cipso_v4_sock_delattr(struct sock *sk)
+{
+}
+
 static inline int cipso_v4_sock_getattr(struct sock *sk,
                                        struct netlbl_lsm_secattr *secattr)
 {
        return -ENOSYS;
 }
 
+static inline int cipso_v4_skbuff_setattr(struct sk_buff *skb,
+                                     const struct cipso_v4_doi *doi_def,
+                                     const struct netlbl_lsm_secattr *secattr)
+{
+       return -ENOSYS;
+}
+
+static inline int cipso_v4_skbuff_delattr(struct sk_buff *skb)
+{
+       return -ENOSYS;
+}
+
 static inline int cipso_v4_skbuff_getattr(const struct sk_buff *skb,
                                          struct netlbl_lsm_secattr *secattr)
 {
        return -ENOSYS;
 }
 
-static inline int cipso_v4_validate(unsigned char **option)
+static inline int cipso_v4_validate(const struct sk_buff *skb,
+                                   unsigned char **option)
 {
        return -ENOSYS;
 }
index e4d2d6baa98388e4d673f5f57ddc20405a3fdb69..17c442a4514e10faf20d9c12af3af5f9b75cef76 100644 (file)
@@ -9,7 +9,7 @@
  */
 
 /*
- * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008
  *
  * 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
@@ -72,8 +72,10 @@ struct cipso_v4_doi;
 /* NetLabel NETLINK protocol version
  *  1: initial version
  *  2: added static labels for unlabeled connections
+ *  3: network selectors added to the NetLabel/LSM domain mapping and the
+ *     CIPSO_V4_MAP_LOCAL CIPSO mapping was added
  */
-#define NETLBL_PROTO_VERSION            2
+#define NETLBL_PROTO_VERSION            3
 
 /* NetLabel NETLINK types/families */
 #define NETLBL_NLTYPE_NONE              0
@@ -87,6 +89,8 @@ struct cipso_v4_doi;
 #define NETLBL_NLTYPE_CIPSOV6_NAME      "NLBL_CIPSOv6"
 #define NETLBL_NLTYPE_UNLABELED         5
 #define NETLBL_NLTYPE_UNLABELED_NAME    "NLBL_UNLBL"
+#define NETLBL_NLTYPE_ADDRSELECT        6
+#define NETLBL_NLTYPE_ADDRSELECT_NAME   "NLBL_ADRSEL"
 
 /*
  * NetLabel - Kernel API for accessing the network packet label mappings.
@@ -200,7 +204,7 @@ struct netlbl_lsm_secattr {
        u32 type;
        char *domain;
        struct netlbl_lsm_cache *cache;
-       union {
+       struct {
                struct {
                        struct netlbl_lsm_secattr_catmap *cat;
                        u32 lvl;
@@ -352,12 +356,9 @@ static inline void netlbl_secattr_free(struct netlbl_lsm_secattr *secattr)
 int netlbl_cfg_map_del(const char *domain, struct netlbl_audit *audit_info);
 int netlbl_cfg_unlbl_add_map(const char *domain,
                             struct netlbl_audit *audit_info);
-int netlbl_cfg_cipsov4_add(struct cipso_v4_doi *doi_def,
-                          struct netlbl_audit *audit_info);
 int netlbl_cfg_cipsov4_add_map(struct cipso_v4_doi *doi_def,
                               const char *domain,
                               struct netlbl_audit *audit_info);
-int netlbl_cfg_cipsov4_del(u32 doi, struct netlbl_audit *audit_info);
 
 /*
  * LSM security attribute operations
@@ -380,12 +381,19 @@ int netlbl_secattr_catmap_setrng(struct netlbl_lsm_secattr_catmap *catmap,
 int netlbl_enabled(void);
 int netlbl_sock_setattr(struct sock *sk,
                        const struct netlbl_lsm_secattr *secattr);
+void netlbl_sock_delattr(struct sock *sk);
 int netlbl_sock_getattr(struct sock *sk,
                        struct netlbl_lsm_secattr *secattr);
+int netlbl_conn_setattr(struct sock *sk,
+                       struct sockaddr *addr,
+                       const struct netlbl_lsm_secattr *secattr);
+int netlbl_skbuff_setattr(struct sk_buff *skb,
+                         u16 family,
+                         const struct netlbl_lsm_secattr *secattr);
 int netlbl_skbuff_getattr(const struct sk_buff *skb,
                          u16 family,
                          struct netlbl_lsm_secattr *secattr);
-void netlbl_skbuff_err(struct sk_buff *skb, int error);
+void netlbl_skbuff_err(struct sk_buff *skb, int error, int gateway);
 
 /*
  * LSM label mapping cache operations
@@ -404,22 +412,12 @@ static inline int netlbl_cfg_unlbl_add_map(const char *domain,
 {
        return -ENOSYS;
 }
-static inline int netlbl_cfg_cipsov4_add(struct cipso_v4_doi *doi_def,
-                                        struct netlbl_audit *audit_info)
-{
-       return -ENOSYS;
-}
 static inline int netlbl_cfg_cipsov4_add_map(struct cipso_v4_doi *doi_def,
                                             const char *domain,
                                             struct netlbl_audit *audit_info)
 {
        return -ENOSYS;
 }
-static inline int netlbl_cfg_cipsov4_del(u32 doi,
-                                        struct netlbl_audit *audit_info)
-{
-       return -ENOSYS;
-}
 static inline int netlbl_secattr_catmap_walk(
                                      struct netlbl_lsm_secattr_catmap *catmap,
                                      u32 offset)
@@ -456,18 +454,35 @@ static inline int netlbl_sock_setattr(struct sock *sk,
 {
        return -ENOSYS;
 }
+static inline void netlbl_sock_delattr(struct sock *sk)
+{
+}
 static inline int netlbl_sock_getattr(struct sock *sk,
                                      struct netlbl_lsm_secattr *secattr)
 {
        return -ENOSYS;
 }
+static inline int netlbl_conn_setattr(struct sock *sk,
+                                     struct sockaddr *addr,
+                                     const struct netlbl_lsm_secattr *secattr)
+{
+       return -ENOSYS;
+}
+static inline int netlbl_skbuff_setattr(struct sk_buff *skb,
+                                     u16 family,
+                                     const struct netlbl_lsm_secattr *secattr)
+{
+       return -ENOSYS;
+}
 static inline int netlbl_skbuff_getattr(const struct sk_buff *skb,
                                        u16 family,
                                        struct netlbl_lsm_secattr *secattr)
 {
        return -ENOSYS;
 }
-static inline void netlbl_skbuff_err(struct sk_buff *skb, int error)
+static inline void netlbl_skbuff_err(struct sk_buff *skb,
+                                    int error,
+                                    int gateway)
 {
        return;
 }
index c1b26fcc0b5c81e8950c77230675bf9314b2c2a8..ca699a3017f39563fc8f6b1d4dc36841e724f125 100644 (file)
@@ -240,6 +240,7 @@ int snd_soc_dapm_sys_add(struct device *dev);
 /* dapm audio pin control and status */
 int snd_soc_dapm_enable_pin(struct snd_soc_codec *codec, char *pin);
 int snd_soc_dapm_disable_pin(struct snd_soc_codec *codec, char *pin);
+int snd_soc_dapm_nc_pin(struct snd_soc_codec *codec, char *pin);
 int snd_soc_dapm_get_pin_status(struct snd_soc_codec *codec, char *pin);
 int snd_soc_dapm_sync(struct snd_soc_codec *codec);
 
index c11da38837e5b7bef935297d3ec0da85c90e1fd7..8a8e2d00c40e1f73a6dafe6c114057014ec15138 100644 (file)
@@ -779,16 +779,6 @@ config MARKERS
 
 source "arch/Kconfig"
 
-config PROC_PAGE_MONITOR
-       default y
-       depends on PROC_FS && MMU
-       bool "Enable /proc page monitoring" if EMBEDDED
-       help
-         Various /proc files exist to monitor process memory utilization:
-         /proc/pid/smaps, /proc/pid/clear_refs, /proc/pid/pagemap,
-         /proc/kpagecount, and /proc/kpageflags. Disabling these
-          interfaces will reduce the size of the kernel by approximately 4kb.
-
 endmenu                # General setup
 
 config HAVE_GENERIC_DMA_COHERENT
index dd68b905941818df3253e6f60558a49b9fbf2ef4..f6006a60df5ddff73990656f73ea7fff55dcf9b8 100644 (file)
@@ -548,7 +548,7 @@ static void do_acct_process(struct bsd_acct_struct *acct,
 #endif
 
        spin_lock_irq(&current->sighand->siglock);
-       tty = current->signal->tty;
+       tty = current->signal->tty;     /* Safe as we hold the siglock */
        ac.ac_tty = tty ? old_encode_dev(tty_devnum(tty)) : 0;
        ac.ac_utime = encode_comp_t(jiffies_to_AHZ(cputime_to_jiffies(pacct->ac_utime)));
        ac.ac_stime = encode_comp_t(jiffies_to_AHZ(cputime_to_jiffies(pacct->ac_stime)));
index 59cedfb040e7864cdfa3199ae2557f236cdd1122..cf5bc2f5f9c3e527ac2ea72ec019d156be72ecb6 100644 (file)
@@ -246,8 +246,8 @@ static int audit_match_perm(struct audit_context *ctx, int mask)
        unsigned n;
        if (unlikely(!ctx))
                return 0;
-
        n = ctx->major;
+
        switch (audit_classify_syscall(ctx->arch, n)) {
        case 0: /* native */
                if ((mask & AUDIT_PERM_WRITE) &&
@@ -1204,13 +1204,13 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
                                 (context->return_valid==AUDITSC_SUCCESS)?"yes":"no",
                                 context->return_code);
 
-       mutex_lock(&tty_mutex);
-       read_lock(&tasklist_lock);
+       spin_lock_irq(&tsk->sighand->siglock);
        if (tsk->signal && tsk->signal->tty && tsk->signal->tty->name)
                tty = tsk->signal->tty->name;
        else
                tty = "(none)";
-       read_unlock(&tasklist_lock);
+       spin_unlock_irq(&tsk->sighand->siglock);
+
        audit_log_format(ab,
                  " a0=%lx a1=%lx a2=%lx a3=%lx items=%d"
                  " ppid=%d pid=%d auid=%u uid=%u gid=%u"
@@ -1230,7 +1230,6 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
                  context->egid, context->sgid, context->fsgid, tty,
                  tsk->sessionid);
 
-       mutex_unlock(&tty_mutex);
 
        audit_log_task_info(ab, tsk);
        if (context->filterkey) {
index 7ce2ebe847964ecd0701c3c74c18994e3eebcf26..30de644a40c4d4d9617d650589f4c90da1e977a2 100644 (file)
@@ -802,6 +802,7 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)
 
        sig->leader = 0;        /* session leadership doesn't inherit */
        sig->tty_old_pgrp = NULL;
+       sig->tty = NULL;
 
        sig->utime = sig->stime = sig->cutime = sig->cstime = cputime_zero;
        sig->gtime = cputime_zero;
@@ -838,6 +839,7 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)
 void __cleanup_signal(struct signal_struct *sig)
 {
        exit_thread_group_keys(sig);
+       tty_kref_put(sig->tty);
        kmem_cache_free(signal_cachep, sig);
 }
 
@@ -1227,7 +1229,8 @@ static struct task_struct *copy_process(unsigned long clone_flags,
                                p->nsproxy->pid_ns->child_reaper = p;
 
                        p->signal->leader_pid = pid;
-                       p->signal->tty = current->signal->tty;
+                       tty_kref_put(p->signal->tty);
+                       p->signal->tty = tty_kref_get(current->signal->tty);
                        set_task_pgrp(p, task_pgrp_nr(current));
                        set_task_session(p, task_session_nr(current));
                        attach_pid(p, PIDTYPE_PGID, task_pgrp(current));
index b51b1567bb5570dfc5b4a19bffd5af865d254e77..a430fd04008b4b9565434ebefa0ee48a62dade90 100644 (file)
@@ -1291,22 +1291,6 @@ static int __init disable_boot_consoles(void)
 }
 late_initcall(disable_boot_consoles);
 
-/**
- * tty_write_message - write a message to a certain tty, not just the console.
- * @tty: the destination tty_struct
- * @msg: the message to write
- *
- * This is used for messages that need to be redirected to a specific tty.
- * We don't put it into the syslog queue right now maybe in the future if
- * really needed.
- */
-void tty_write_message(struct tty_struct *tty, char *msg)
-{
-       if (tty && tty->ops->write)
-               tty->ops->write(tty, msg, strlen(msg));
-       return;
-}
-
 #if defined CONFIG_PRINTK
 
 /*
index bbe6b31c3c560d864285ad696d0e885f0ee3e5d6..ad958c1ec70859704afc3ae3d444c03914b37a6b 100644 (file)
@@ -333,12 +333,10 @@ void proc_sched_show_task(struct task_struct *p, struct seq_file *m)
        unsigned long flags;
        int num_threads = 1;
 
-       rcu_read_lock();
        if (lock_task_sighand(p, &flags)) {
                num_threads = atomic_read(&p->signal->count);
                unlock_task_sighand(p, &flags);
        }
-       rcu_read_unlock();
 
        SEQ_printf(m, "%s (%d, #threads: %d)\n", p->comm, p->pid, num_threads);
        SEQ_printf(m,
index 038a7bc0901d20f90f841c5e4326fc1f2f2b963f..234d9454294e12b6f366abd75ce70009e3cde3af 100644 (file)
@@ -1060,9 +1060,7 @@ asmlinkage long sys_setsid(void)
        group_leader->signal->leader = 1;
        __set_special_pids(sid);
 
-       spin_lock(&group_leader->sighand->siglock);
-       group_leader->signal->tty = NULL;
-       spin_unlock(&group_leader->sighand->siglock);
+       proc_clear_tty(group_leader);
 
        err = session;
 out:
index 1bf369bd44234e829905d9a565577537c040c846..c468c3c6dfc525e0c413eae9f90a8b77d77887f0 100644 (file)
@@ -80,7 +80,6 @@ extern int pid_max_min, pid_max_max;
 extern int sysctl_drop_caches;
 extern int percpu_pagelist_fraction;
 extern int compat_log;
-extern int maps_protect;
 extern int latencytop_enabled;
 extern int sysctl_nr_open_min, sysctl_nr_open_max;
 #ifdef CONFIG_RCU_TORTURE_TEST
@@ -807,16 +806,6 @@ static struct ctl_table kern_table[] = {
                .mode           = 0644,
                .proc_handler   = &proc_dointvec,
        },
-#endif
-#ifdef CONFIG_PROC_FS
-       {
-               .ctl_name       = CTL_UNNUMBERED,
-               .procname       = "maps_protect",
-               .data           = &maps_protect,
-               .maxlen         = sizeof(int),
-               .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
-       },
 #endif
        {
                .ctl_name       = CTL_UNNUMBERED,
index 04fb4f1ab88e7e0c87e646afded96e962251fb61..bf66d0191baf57e36a72143335f0d3d93e24d548 100644 (file)
 #include <linux/migrate.h>
 #include <linux/highmem.h>
 #include <linux/seq_file.h>
+#include <linux/magic.h>
 
 #include <asm/uaccess.h>
 #include <asm/div64.h>
 #include <asm/pgtable.h>
 
-/* This magic number is used in glibc for posix shared memory */
-#define TMPFS_MAGIC    0x01021994
-
 #define ENTRIES_PER_PAGE (PAGE_CACHE_SIZE/sizeof(unsigned long))
 #define ENTRIES_PER_PAGEPAGE (ENTRIES_PER_PAGE*ENTRIES_PER_PAGE)
 #define BLOCKS_PER_PAGE  (PAGE_CACHE_SIZE/512)
index 2c0e4572cc9042e76fca92f5c08303d1489f513c..490e035c6d90d231aee5514ac8d4a3f262ef0a4d 100644 (file)
@@ -13,7 +13,7 @@
  */
 
 /*
- * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008
  *
  * 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
 #include <asm/bug.h>
 #include <asm/unaligned.h>
 
-struct cipso_v4_domhsh_entry {
-       char *domain;
-       u32 valid;
-       struct list_head list;
-       struct rcu_head rcu;
-};
-
 /* List of available DOI definitions */
-/* XXX - Updates should be minimal so having a single lock for the
- * cipso_v4_doi_list and the cipso_v4_doi_list->dom_list should be
- * okay. */
 /* XXX - This currently assumes a minimal number of different DOIs in use,
  * if in practice there are a lot of different DOIs this list should
  * probably be turned into a hash table or something similar so we
@@ -119,6 +109,19 @@ int cipso_v4_rbm_strictvalid = 1;
  * be omitted. */
 #define CIPSO_V4_TAG_RNG_CAT_MAX      8
 
+/* Base length of the local tag (non-standard tag).
+ *  Tag definition (may change between kernel versions)
+ *
+ * 0          8          16         24         32
+ * +----------+----------+----------+----------+
+ * | 10000000 | 00000110 | 32-bit secid value  |
+ * +----------+----------+----------+----------+
+ * | in (host byte order)|
+ * +----------+----------+
+ *
+ */
+#define CIPSO_V4_TAG_LOC_BLEN         6
+
 /*
  * Helper Functions
  */
@@ -193,25 +196,6 @@ static void cipso_v4_bitmap_setbit(unsigned char *bitmap,
                bitmap[byte_spot] &= ~bitmask;
 }
 
-/**
- * cipso_v4_doi_domhsh_free - Frees a domain list entry
- * @entry: the entry's RCU field
- *
- * Description:
- * This function is designed to be used as a callback to the call_rcu()
- * function so that the memory allocated to a domain list entry can be released
- * safely.
- *
- */
-static void cipso_v4_doi_domhsh_free(struct rcu_head *entry)
-{
-       struct cipso_v4_domhsh_entry *ptr;
-
-       ptr = container_of(entry, struct cipso_v4_domhsh_entry, rcu);
-       kfree(ptr->domain);
-       kfree(ptr);
-}
-
 /**
  * cipso_v4_cache_entry_free - Frees a cache entry
  * @entry: the entry to free
@@ -457,7 +441,7 @@ static struct cipso_v4_doi *cipso_v4_doi_search(u32 doi)
        struct cipso_v4_doi *iter;
 
        list_for_each_entry_rcu(iter, &cipso_v4_doi_list, list)
-               if (iter->doi == doi && iter->valid)
+               if (iter->doi == doi && atomic_read(&iter->refcount))
                        return iter;
        return NULL;
 }
@@ -496,14 +480,17 @@ int cipso_v4_doi_add(struct cipso_v4_doi *doi_def)
                        if (doi_def->type != CIPSO_V4_MAP_PASS)
                                return -EINVAL;
                        break;
+               case CIPSO_V4_TAG_LOCAL:
+                       if (doi_def->type != CIPSO_V4_MAP_LOCAL)
+                               return -EINVAL;
+                       break;
                default:
                        return -EINVAL;
                }
        }
 
-       doi_def->valid = 1;
+       atomic_set(&doi_def->refcount, 1);
        INIT_RCU_HEAD(&doi_def->rcu);
-       INIT_LIST_HEAD(&doi_def->dom_list);
 
        spin_lock(&cipso_v4_doi_list_lock);
        if (cipso_v4_doi_search(doi_def->doi) != NULL)
@@ -518,60 +505,130 @@ doi_add_failure:
        return -EEXIST;
 }
 
+/**
+ * cipso_v4_doi_free - Frees a DOI definition
+ * @entry: the entry's RCU field
+ *
+ * Description:
+ * This function frees all of the memory associated with a DOI definition.
+ *
+ */
+void cipso_v4_doi_free(struct cipso_v4_doi *doi_def)
+{
+       if (doi_def == NULL)
+               return;
+
+       switch (doi_def->type) {
+       case CIPSO_V4_MAP_TRANS:
+               kfree(doi_def->map.std->lvl.cipso);
+               kfree(doi_def->map.std->lvl.local);
+               kfree(doi_def->map.std->cat.cipso);
+               kfree(doi_def->map.std->cat.local);
+               break;
+       }
+       kfree(doi_def);
+}
+
+/**
+ * cipso_v4_doi_free_rcu - Frees a DOI definition via the RCU pointer
+ * @entry: the entry's RCU field
+ *
+ * Description:
+ * This function is designed to be used as a callback to the call_rcu()
+ * function so that the memory allocated to the DOI definition can be released
+ * safely.
+ *
+ */
+static void cipso_v4_doi_free_rcu(struct rcu_head *entry)
+{
+       struct cipso_v4_doi *doi_def;
+
+       doi_def = container_of(entry, struct cipso_v4_doi, rcu);
+       cipso_v4_doi_free(doi_def);
+}
+
 /**
  * cipso_v4_doi_remove - Remove an existing DOI from the CIPSO protocol engine
  * @doi: the DOI value
  * @audit_secid: the LSM secid to use in the audit message
- * @callback: the DOI cleanup/free callback
  *
  * Description:
- * Removes a DOI definition from the CIPSO engine, @callback is called to
- * free any memory.  The NetLabel routines will be called to release their own
- * LSM domain mappings as well as our own domain list.  Returns zero on
- * success and negative values on failure.
+ * Removes a DOI definition from the CIPSO engine.  The NetLabel routines will
+ * be called to release their own LSM domain mappings as well as our own
+ * domain list.  Returns zero on success and negative values on failure.
  *
  */
-int cipso_v4_doi_remove(u32 doi,
-                       struct netlbl_audit *audit_info,
-                       void (*callback) (struct rcu_head * head))
+int cipso_v4_doi_remove(u32 doi, struct netlbl_audit *audit_info)
 {
        struct cipso_v4_doi *doi_def;
-       struct cipso_v4_domhsh_entry *dom_iter;
 
        spin_lock(&cipso_v4_doi_list_lock);
        doi_def = cipso_v4_doi_search(doi);
-       if (doi_def != NULL) {
-               doi_def->valid = 0;
-               list_del_rcu(&doi_def->list);
+       if (doi_def == NULL) {
                spin_unlock(&cipso_v4_doi_list_lock);
-               rcu_read_lock();
-               list_for_each_entry_rcu(dom_iter, &doi_def->dom_list, list)
-                       if (dom_iter->valid)
-                               netlbl_cfg_map_del(dom_iter->domain,
-                                                  audit_info);
-               rcu_read_unlock();
-               cipso_v4_cache_invalidate();
-               call_rcu(&doi_def->rcu, callback);
-               return 0;
+               return -ENOENT;
+       }
+       if (!atomic_dec_and_test(&doi_def->refcount)) {
+               spin_unlock(&cipso_v4_doi_list_lock);
+               return -EBUSY;
        }
+       list_del_rcu(&doi_def->list);
        spin_unlock(&cipso_v4_doi_list_lock);
 
-       return -ENOENT;
+       cipso_v4_cache_invalidate();
+       call_rcu(&doi_def->rcu, cipso_v4_doi_free_rcu);
+
+       return 0;
 }
 
 /**
- * cipso_v4_doi_getdef - Returns a pointer to a valid DOI definition
+ * cipso_v4_doi_getdef - Returns a reference to a valid DOI definition
  * @doi: the DOI value
  *
  * Description:
  * Searches for a valid DOI definition and if one is found it is returned to
  * the caller.  Otherwise NULL is returned.  The caller must ensure that
- * rcu_read_lock() is held while accessing the returned definition.
+ * rcu_read_lock() is held while accessing the returned definition and the DOI
+ * definition reference count is decremented when the caller is done.
  *
  */
 struct cipso_v4_doi *cipso_v4_doi_getdef(u32 doi)
 {
-       return cipso_v4_doi_search(doi);
+       struct cipso_v4_doi *doi_def;
+
+       rcu_read_lock();
+       doi_def = cipso_v4_doi_search(doi);
+       if (doi_def == NULL)
+               goto doi_getdef_return;
+       if (!atomic_inc_not_zero(&doi_def->refcount))
+               doi_def = NULL;
+
+doi_getdef_return:
+       rcu_read_unlock();
+       return doi_def;
+}
+
+/**
+ * cipso_v4_doi_putdef - Releases a reference for the given DOI definition
+ * @doi_def: the DOI definition
+ *
+ * Description:
+ * Releases a DOI definition reference obtained from cipso_v4_doi_getdef().
+ *
+ */
+void cipso_v4_doi_putdef(struct cipso_v4_doi *doi_def)
+{
+       if (doi_def == NULL)
+               return;
+
+       if (!atomic_dec_and_test(&doi_def->refcount))
+               return;
+       spin_lock(&cipso_v4_doi_list_lock);
+       list_del_rcu(&doi_def->list);
+       spin_unlock(&cipso_v4_doi_list_lock);
+
+       cipso_v4_cache_invalidate();
+       call_rcu(&doi_def->rcu, cipso_v4_doi_free_rcu);
 }
 
 /**
@@ -597,7 +654,7 @@ int cipso_v4_doi_walk(u32 *skip_cnt,
 
        rcu_read_lock();
        list_for_each_entry_rcu(iter_doi, &cipso_v4_doi_list, list)
-               if (iter_doi->valid) {
+               if (atomic_read(&iter_doi->refcount) > 0) {
                        if (doi_cnt++ < *skip_cnt)
                                continue;
                        ret_val = callback(iter_doi, cb_arg);
@@ -613,85 +670,6 @@ doi_walk_return:
        return ret_val;
 }
 
-/**
- * cipso_v4_doi_domhsh_add - Adds a domain entry to a DOI definition
- * @doi_def: the DOI definition
- * @domain: the domain to add
- *
- * Description:
- * Adds the @domain to the DOI specified by @doi_def, this function
- * should only be called by external functions (i.e. NetLabel).  This function
- * does allocate memory.  Returns zero on success, negative values on failure.
- *
- */
-int cipso_v4_doi_domhsh_add(struct cipso_v4_doi *doi_def, const char *domain)
-{
-       struct cipso_v4_domhsh_entry *iter;
-       struct cipso_v4_domhsh_entry *new_dom;
-
-       new_dom = kzalloc(sizeof(*new_dom), GFP_KERNEL);
-       if (new_dom == NULL)
-               return -ENOMEM;
-       if (domain) {
-               new_dom->domain = kstrdup(domain, GFP_KERNEL);
-               if (new_dom->domain == NULL) {
-                       kfree(new_dom);
-                       return -ENOMEM;
-               }
-       }
-       new_dom->valid = 1;
-       INIT_RCU_HEAD(&new_dom->rcu);
-
-       spin_lock(&cipso_v4_doi_list_lock);
-       list_for_each_entry(iter, &doi_def->dom_list, list)
-               if (iter->valid &&
-                   ((domain != NULL && iter->domain != NULL &&
-                     strcmp(iter->domain, domain) == 0) ||
-                    (domain == NULL && iter->domain == NULL))) {
-                       spin_unlock(&cipso_v4_doi_list_lock);
-                       kfree(new_dom->domain);
-                       kfree(new_dom);
-                       return -EEXIST;
-               }
-       list_add_tail_rcu(&new_dom->list, &doi_def->dom_list);
-       spin_unlock(&cipso_v4_doi_list_lock);
-
-       return 0;
-}
-
-/**
- * cipso_v4_doi_domhsh_remove - Removes a domain entry from a DOI definition
- * @doi_def: the DOI definition
- * @domain: the domain to remove
- *
- * Description:
- * Removes the @domain from the DOI specified by @doi_def, this function
- * should only be called by external functions (i.e. NetLabel).   Returns zero
- * on success and negative values on error.
- *
- */
-int cipso_v4_doi_domhsh_remove(struct cipso_v4_doi *doi_def,
-                              const char *domain)
-{
-       struct cipso_v4_domhsh_entry *iter;
-
-       spin_lock(&cipso_v4_doi_list_lock);
-       list_for_each_entry(iter, &doi_def->dom_list, list)
-               if (iter->valid &&
-                   ((domain != NULL && iter->domain != NULL &&
-                     strcmp(iter->domain, domain) == 0) ||
-                    (domain == NULL && iter->domain == NULL))) {
-                       iter->valid = 0;
-                       list_del_rcu(&iter->list);
-                       spin_unlock(&cipso_v4_doi_list_lock);
-                       call_rcu(&iter->rcu, cipso_v4_doi_domhsh_free);
-                       return 0;
-               }
-       spin_unlock(&cipso_v4_doi_list_lock);
-
-       return -ENOENT;
-}
-
 /*
  * Label Mapping Functions
  */
@@ -712,7 +690,7 @@ static int cipso_v4_map_lvl_valid(const struct cipso_v4_doi *doi_def, u8 level)
        switch (doi_def->type) {
        case CIPSO_V4_MAP_PASS:
                return 0;
-       case CIPSO_V4_MAP_STD:
+       case CIPSO_V4_MAP_TRANS:
                if (doi_def->map.std->lvl.cipso[level] < CIPSO_V4_INV_LVL)
                        return 0;
                break;
@@ -741,7 +719,7 @@ static int cipso_v4_map_lvl_hton(const struct cipso_v4_doi *doi_def,
        case CIPSO_V4_MAP_PASS:
                *net_lvl = host_lvl;
                return 0;
-       case CIPSO_V4_MAP_STD:
+       case CIPSO_V4_MAP_TRANS:
                if (host_lvl < doi_def->map.std->lvl.local_size &&
                    doi_def->map.std->lvl.local[host_lvl] < CIPSO_V4_INV_LVL) {
                        *net_lvl = doi_def->map.std->lvl.local[host_lvl];
@@ -775,7 +753,7 @@ static int cipso_v4_map_lvl_ntoh(const struct cipso_v4_doi *doi_def,
        case CIPSO_V4_MAP_PASS:
                *host_lvl = net_lvl;
                return 0;
-       case CIPSO_V4_MAP_STD:
+       case CIPSO_V4_MAP_TRANS:
                map_tbl = doi_def->map.std;
                if (net_lvl < map_tbl->lvl.cipso_size &&
                    map_tbl->lvl.cipso[net_lvl] < CIPSO_V4_INV_LVL) {
@@ -812,7 +790,7 @@ static int cipso_v4_map_cat_rbm_valid(const struct cipso_v4_doi *doi_def,
        switch (doi_def->type) {
        case CIPSO_V4_MAP_PASS:
                return 0;
-       case CIPSO_V4_MAP_STD:
+       case CIPSO_V4_MAP_TRANS:
                cipso_cat_size = doi_def->map.std->cat.cipso_size;
                cipso_array = doi_def->map.std->cat.cipso;
                for (;;) {
@@ -860,7 +838,7 @@ static int cipso_v4_map_cat_rbm_hton(const struct cipso_v4_doi *doi_def,
        u32 host_cat_size = 0;
        u32 *host_cat_array = NULL;
 
-       if (doi_def->type == CIPSO_V4_MAP_STD) {
+       if (doi_def->type == CIPSO_V4_MAP_TRANS) {
                host_cat_size = doi_def->map.std->cat.local_size;
                host_cat_array = doi_def->map.std->cat.local;
        }
@@ -875,7 +853,7 @@ static int cipso_v4_map_cat_rbm_hton(const struct cipso_v4_doi *doi_def,
                case CIPSO_V4_MAP_PASS:
                        net_spot = host_spot;
                        break;
-               case CIPSO_V4_MAP_STD:
+               case CIPSO_V4_MAP_TRANS:
                        if (host_spot >= host_cat_size)
                                return -EPERM;
                        net_spot = host_cat_array[host_spot];
@@ -921,7 +899,7 @@ static int cipso_v4_map_cat_rbm_ntoh(const struct cipso_v4_doi *doi_def,
        u32 net_cat_size = 0;
        u32 *net_cat_array = NULL;
 
-       if (doi_def->type == CIPSO_V4_MAP_STD) {
+       if (doi_def->type == CIPSO_V4_MAP_TRANS) {
                net_cat_size = doi_def->map.std->cat.cipso_size;
                net_cat_array = doi_def->map.std->cat.cipso;
        }
@@ -941,7 +919,7 @@ static int cipso_v4_map_cat_rbm_ntoh(const struct cipso_v4_doi *doi_def,
                case CIPSO_V4_MAP_PASS:
                        host_spot = net_spot;
                        break;
-               case CIPSO_V4_MAP_STD:
+               case CIPSO_V4_MAP_TRANS:
                        if (net_spot >= net_cat_size)
                                return -EPERM;
                        host_spot = net_cat_array[net_spot];
@@ -1277,7 +1255,7 @@ static int cipso_v4_gentag_rbm(const struct cipso_v4_doi *doi_def,
        } else
                tag_len = 4;
 
-       buffer[0] = 0x01;
+       buffer[0] = CIPSO_V4_TAG_RBITMAP;
        buffer[1] = tag_len;
        buffer[3] = level;
 
@@ -1373,7 +1351,7 @@ static int cipso_v4_gentag_enum(const struct cipso_v4_doi *doi_def,
        } else
                tag_len = 4;
 
-       buffer[0] = 0x02;
+       buffer[0] = CIPSO_V4_TAG_ENUM;
        buffer[1] = tag_len;
        buffer[3] = level;
 
@@ -1469,7 +1447,7 @@ static int cipso_v4_gentag_rng(const struct cipso_v4_doi *doi_def,
        } else
                tag_len = 4;
 
-       buffer[0] = 0x05;
+       buffer[0] = CIPSO_V4_TAG_RANGE;
        buffer[1] = tag_len;
        buffer[3] = level;
 
@@ -1522,6 +1500,54 @@ static int cipso_v4_parsetag_rng(const struct cipso_v4_doi *doi_def,
        return 0;
 }
 
+/**
+ * cipso_v4_gentag_loc - Generate a CIPSO local tag (non-standard)
+ * @doi_def: the DOI definition
+ * @secattr: the security attributes
+ * @buffer: the option buffer
+ * @buffer_len: length of buffer in bytes
+ *
+ * Description:
+ * Generate a CIPSO option using the local tag.  Returns the size of the tag
+ * on success, negative values on failure.
+ *
+ */
+static int cipso_v4_gentag_loc(const struct cipso_v4_doi *doi_def,
+                              const struct netlbl_lsm_secattr *secattr,
+                              unsigned char *buffer,
+                              u32 buffer_len)
+{
+       if (!(secattr->flags & NETLBL_SECATTR_SECID))
+               return -EPERM;
+
+       buffer[0] = CIPSO_V4_TAG_LOCAL;
+       buffer[1] = CIPSO_V4_TAG_LOC_BLEN;
+       *(u32 *)&buffer[2] = secattr->attr.secid;
+
+       return CIPSO_V4_TAG_LOC_BLEN;
+}
+
+/**
+ * cipso_v4_parsetag_loc - Parse a CIPSO local tag
+ * @doi_def: the DOI definition
+ * @tag: the CIPSO tag
+ * @secattr: the security attributes
+ *
+ * Description:
+ * Parse a CIPSO local tag and return the security attributes in @secattr.
+ * Return zero on success, negatives values on failure.
+ *
+ */
+static int cipso_v4_parsetag_loc(const struct cipso_v4_doi *doi_def,
+                                const unsigned char *tag,
+                                struct netlbl_lsm_secattr *secattr)
+{
+       secattr->attr.secid = *(u32 *)&tag[2];
+       secattr->flags |= NETLBL_SECATTR_SECID;
+
+       return 0;
+}
+
 /**
  * cipso_v4_validate - Validate a CIPSO option
  * @option: the start of the option, on error it is set to point to the error
@@ -1541,7 +1567,7 @@ static int cipso_v4_parsetag_rng(const struct cipso_v4_doi *doi_def,
  *   that is unrecognized."
  *
  */
-int cipso_v4_validate(unsigned char **option)
+int cipso_v4_validate(const struct sk_buff *skb, unsigned char **option)
 {
        unsigned char *opt = *option;
        unsigned char *tag;
@@ -1566,7 +1592,7 @@ int cipso_v4_validate(unsigned char **option)
                goto validate_return_locked;
        }
 
-       opt_iter = 6;
+       opt_iter = CIPSO_V4_HDR_LEN;
        tag = opt + opt_iter;
        while (opt_iter < opt_len) {
                for (tag_iter = 0; doi_def->tags[tag_iter] != tag[0];)
@@ -1584,7 +1610,7 @@ int cipso_v4_validate(unsigned char **option)
 
                switch (tag[0]) {
                case CIPSO_V4_TAG_RBITMAP:
-                       if (tag_len < 4) {
+                       if (tag_len < CIPSO_V4_TAG_RBM_BLEN) {
                                err_offset = opt_iter + 1;
                                goto validate_return_locked;
                        }
@@ -1602,7 +1628,7 @@ int cipso_v4_validate(unsigned char **option)
                                        err_offset = opt_iter + 3;
                                        goto validate_return_locked;
                                }
-                               if (tag_len > 4 &&
+                               if (tag_len > CIPSO_V4_TAG_RBM_BLEN &&
                                    cipso_v4_map_cat_rbm_valid(doi_def,
                                                            &tag[4],
                                                            tag_len - 4) < 0) {
@@ -1612,7 +1638,7 @@ int cipso_v4_validate(unsigned char **option)
                        }
                        break;
                case CIPSO_V4_TAG_ENUM:
-                       if (tag_len < 4) {
+                       if (tag_len < CIPSO_V4_TAG_ENUM_BLEN) {
                                err_offset = opt_iter + 1;
                                goto validate_return_locked;
                        }
@@ -1622,7 +1648,7 @@ int cipso_v4_validate(unsigned char **option)
                                err_offset = opt_iter + 3;
                                goto validate_return_locked;
                        }
-                       if (tag_len > 4 &&
+                       if (tag_len > CIPSO_V4_TAG_ENUM_BLEN &&
                            cipso_v4_map_cat_enum_valid(doi_def,
                                                        &tag[4],
                                                        tag_len - 4) < 0) {
@@ -1631,7 +1657,7 @@ int cipso_v4_validate(unsigned char **option)
                        }
                        break;
                case CIPSO_V4_TAG_RANGE:
-                       if (tag_len < 4) {
+                       if (tag_len < CIPSO_V4_TAG_RNG_BLEN) {
                                err_offset = opt_iter + 1;
                                goto validate_return_locked;
                        }
@@ -1641,7 +1667,7 @@ int cipso_v4_validate(unsigned char **option)
                                err_offset = opt_iter + 3;
                                goto validate_return_locked;
                        }
-                       if (tag_len > 4 &&
+                       if (tag_len > CIPSO_V4_TAG_RNG_BLEN &&
                            cipso_v4_map_cat_rng_valid(doi_def,
                                                       &tag[4],
                                                       tag_len - 4) < 0) {
@@ -1649,6 +1675,19 @@ int cipso_v4_validate(unsigned char **option)
                                goto validate_return_locked;
                        }
                        break;
+               case CIPSO_V4_TAG_LOCAL:
+                       /* This is a non-standard tag that we only allow for
+                        * local connections, so if the incoming interface is
+                        * not the loopback device drop the packet. */
+                       if (!(skb->dev->flags & IFF_LOOPBACK)) {
+                               err_offset = opt_iter;
+                               goto validate_return_locked;
+                       }
+                       if (tag_len != CIPSO_V4_TAG_LOC_BLEN) {
+                               err_offset = opt_iter + 1;
+                               goto validate_return_locked;
+                       }
+                       break;
                default:
                        err_offset = opt_iter;
                        goto validate_return_locked;
@@ -1704,48 +1743,27 @@ void cipso_v4_error(struct sk_buff *skb, int error, u32 gateway)
 }
 
 /**
- * cipso_v4_sock_setattr - Add a CIPSO option to a socket
- * @sk: the socket
+ * cipso_v4_genopt - Generate a CIPSO option
+ * @buf: the option buffer
+ * @buf_len: the size of opt_buf
  * @doi_def: the CIPSO DOI to use
- * @secattr: the specific security attributes of the socket
+ * @secattr: the security attributes
  *
  * Description:
- * Set the CIPSO option on the given socket using the DOI definition and
- * security attributes passed to the function.  This function requires
- * exclusive access to @sk, which means it either needs to be in the
- * process of being created or locked.  Returns zero on success and negative
- * values on failure.
+ * Generate a CIPSO option using the DOI definition and security attributes
+ * passed to the function.  Returns the length of the option on success and
+ * negative values on failure.
  *
  */
-int cipso_v4_sock_setattr(struct sock *sk,
-                         const struct cipso_v4_doi *doi_def,
-                         const struct netlbl_lsm_secattr *secattr)
+static int cipso_v4_genopt(unsigned char *buf, u32 buf_len,
+                          const struct cipso_v4_doi *doi_def,
+                          const struct netlbl_lsm_secattr *secattr)
 {
-       int ret_val = -EPERM;
+       int ret_val;
        u32 iter;
-       unsigned char *buf;
-       u32 buf_len = 0;
-       u32 opt_len;
-       struct ip_options *opt = NULL;
-       struct inet_sock *sk_inet;
-       struct inet_connection_sock *sk_conn;
 
-       /* In the case of sock_create_lite(), the sock->sk field is not
-        * defined yet but it is not a problem as the only users of these
-        * "lite" PF_INET sockets are functions which do an accept() call
-        * afterwards so we will label the socket as part of the accept(). */
-       if (sk == NULL)
-               return 0;
-
-       /* We allocate the maximum CIPSO option size here so we are probably
-        * being a little wasteful, but it makes our life _much_ easier later
-        * on and after all we are only talking about 40 bytes. */
-       buf_len = CIPSO_V4_OPT_LEN_MAX;
-       buf = kmalloc(buf_len, GFP_ATOMIC);
-       if (buf == NULL) {
-               ret_val = -ENOMEM;
-               goto socket_setattr_failure;
-       }
+       if (buf_len <= CIPSO_V4_HDR_LEN)
+               return -ENOSPC;
 
        /* XXX - This code assumes only one tag per CIPSO option which isn't
         * really a good assumption to make but since we only support the MAC
@@ -1772,9 +1790,14 @@ int cipso_v4_sock_setattr(struct sock *sk,
                                                   &buf[CIPSO_V4_HDR_LEN],
                                                   buf_len - CIPSO_V4_HDR_LEN);
                        break;
+               case CIPSO_V4_TAG_LOCAL:
+                       ret_val = cipso_v4_gentag_loc(doi_def,
+                                                  secattr,
+                                                  &buf[CIPSO_V4_HDR_LEN],
+                                                  buf_len - CIPSO_V4_HDR_LEN);
+                       break;
                default:
-                       ret_val = -EPERM;
-                       goto socket_setattr_failure;
+                       return -EPERM;
                }
 
                iter++;
@@ -1782,9 +1805,58 @@ int cipso_v4_sock_setattr(struct sock *sk,
                 iter < CIPSO_V4_TAG_MAXCNT &&
                 doi_def->tags[iter] != CIPSO_V4_TAG_INVALID);
        if (ret_val < 0)
-               goto socket_setattr_failure;
+               return ret_val;
        cipso_v4_gentag_hdr(doi_def, buf, ret_val);
-       buf_len = CIPSO_V4_HDR_LEN + ret_val;
+       return CIPSO_V4_HDR_LEN + ret_val;
+}
+
+/**
+ * cipso_v4_sock_setattr - Add a CIPSO option to a socket
+ * @sk: the socket
+ * @doi_def: the CIPSO DOI to use
+ * @secattr: the specific security attributes of the socket
+ *
+ * Description:
+ * Set the CIPSO option on the given socket using the DOI definition and
+ * security attributes passed to the function.  This function requires
+ * exclusive access to @sk, which means it either needs to be in the
+ * process of being created or locked.  Returns zero on success and negative
+ * values on failure.
+ *
+ */
+int cipso_v4_sock_setattr(struct sock *sk,
+                         const struct cipso_v4_doi *doi_def,
+                         const struct netlbl_lsm_secattr *secattr)
+{
+       int ret_val = -EPERM;
+       unsigned char *buf = NULL;
+       u32 buf_len;
+       u32 opt_len;
+       struct ip_options *opt = NULL;
+       struct inet_sock *sk_inet;
+       struct inet_connection_sock *sk_conn;
+
+       /* In the case of sock_create_lite(), the sock->sk field is not
+        * defined yet but it is not a problem as the only users of these
+        * "lite" PF_INET sockets are functions which do an accept() call
+        * afterwards so we will label the socket as part of the accept(). */
+       if (sk == NULL)
+               return 0;
+
+       /* We allocate the maximum CIPSO option size here so we are probably
+        * being a little wasteful, but it makes our life _much_ easier later
+        * on and after all we are only talking about 40 bytes. */
+       buf_len = CIPSO_V4_OPT_LEN_MAX;
+       buf = kmalloc(buf_len, GFP_ATOMIC);
+       if (buf == NULL) {
+               ret_val = -ENOMEM;
+               goto socket_setattr_failure;
+       }
+
+       ret_val = cipso_v4_genopt(buf, buf_len, doi_def, secattr);
+       if (ret_val < 0)
+               goto socket_setattr_failure;
+       buf_len = ret_val;
 
        /* We can't use ip_options_get() directly because it makes a call to
         * ip_options_get_alloc() which allocates memory with GFP_KERNEL and
@@ -1821,6 +1893,80 @@ socket_setattr_failure:
        return ret_val;
 }
 
+/**
+ * cipso_v4_sock_delattr - Delete the CIPSO option from a socket
+ * @sk: the socket
+ *
+ * Description:
+ * Removes the CIPSO option from a socket, if present.
+ *
+ */
+void cipso_v4_sock_delattr(struct sock *sk)
+{
+       u8 hdr_delta;
+       struct ip_options *opt;
+       struct inet_sock *sk_inet;
+
+       sk_inet = inet_sk(sk);
+       opt = sk_inet->opt;
+       if (opt == NULL || opt->cipso == 0)
+               return;
+
+       if (opt->srr || opt->rr || opt->ts || opt->router_alert) {
+               u8 cipso_len;
+               u8 cipso_off;
+               unsigned char *cipso_ptr;
+               int iter;
+               int optlen_new;
+
+               cipso_off = opt->cipso - sizeof(struct iphdr);
+               cipso_ptr = &opt->__data[cipso_off];
+               cipso_len = cipso_ptr[1];
+
+               if (opt->srr > opt->cipso)
+                       opt->srr -= cipso_len;
+               if (opt->rr > opt->cipso)
+                       opt->rr -= cipso_len;
+               if (opt->ts > opt->cipso)
+                       opt->ts -= cipso_len;
+               if (opt->router_alert > opt->cipso)
+                       opt->router_alert -= cipso_len;
+               opt->cipso = 0;
+
+               memmove(cipso_ptr, cipso_ptr + cipso_len,
+                       opt->optlen - cipso_off - cipso_len);
+
+               /* determining the new total option length is tricky because of
+                * the padding necessary, the only thing i can think to do at
+                * this point is walk the options one-by-one, skipping the
+                * padding at the end to determine the actual option size and
+                * from there we can determine the new total option length */
+               iter = 0;
+               optlen_new = 0;
+               while (iter < opt->optlen)
+                       if (opt->__data[iter] != IPOPT_NOP) {
+                               iter += opt->__data[iter + 1];
+                               optlen_new = iter;
+                       } else
+                               iter++;
+               hdr_delta = opt->optlen;
+               opt->optlen = (optlen_new + 3) & ~3;
+               hdr_delta -= opt->optlen;
+       } else {
+               /* only the cipso option was present on the socket so we can
+                * remove the entire option struct */
+               sk_inet->opt = NULL;
+               hdr_delta = opt->optlen;
+               kfree(opt);
+       }
+
+       if (sk_inet->is_icsk && hdr_delta > 0) {
+               struct inet_connection_sock *sk_conn = inet_csk(sk);
+               sk_conn->icsk_ext_hdr_len -= hdr_delta;
+               sk_conn->icsk_sync_mss(sk, sk_conn->icsk_pmtu_cookie);
+       }
+}
+
 /**
  * cipso_v4_getattr - Helper function for the cipso_v4_*_getattr functions
  * @cipso: the CIPSO v4 option
@@ -1859,6 +2005,9 @@ static int cipso_v4_getattr(const unsigned char *cipso,
        case CIPSO_V4_TAG_RANGE:
                ret_val = cipso_v4_parsetag_rng(doi_def, &cipso[6], secattr);
                break;
+       case CIPSO_V4_TAG_LOCAL:
+               ret_val = cipso_v4_parsetag_loc(doi_def, &cipso[6], secattr);
+               break;
        }
        if (ret_val == 0)
                secattr->type = NETLBL_NLTYPE_CIPSOV4;
@@ -1892,6 +2041,123 @@ int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr)
                                secattr);
 }
 
+/**
+ * cipso_v4_skbuff_setattr - Set the CIPSO option on a packet
+ * @skb: the packet
+ * @secattr: the security attributes
+ *
+ * Description:
+ * Set the CIPSO option on the given packet based on the security attributes.
+ * Returns a pointer to the IP header on success and NULL on failure.
+ *
+ */
+int cipso_v4_skbuff_setattr(struct sk_buff *skb,
+                           const struct cipso_v4_doi *doi_def,
+                           const struct netlbl_lsm_secattr *secattr)
+{
+       int ret_val;
+       struct iphdr *iph;
+       struct ip_options *opt = &IPCB(skb)->opt;
+       unsigned char buf[CIPSO_V4_OPT_LEN_MAX];
+       u32 buf_len = CIPSO_V4_OPT_LEN_MAX;
+       u32 opt_len;
+       int len_delta;
+
+       buf_len = cipso_v4_genopt(buf, buf_len, doi_def, secattr);
+       if (buf_len < 0)
+               return buf_len;
+       opt_len = (buf_len + 3) & ~3;
+
+       /* we overwrite any existing options to ensure that we have enough
+        * room for the CIPSO option, the reason is that we _need_ to guarantee
+        * that the security label is applied to the packet - we do the same
+        * thing when using the socket options and it hasn't caused a problem,
+        * if we need to we can always revisit this choice later */
+
+       len_delta = opt_len - opt->optlen;
+       /* if we don't ensure enough headroom we could panic on the skb_push()
+        * call below so make sure we have enough, we are also "mangling" the
+        * packet so we should probably do a copy-on-write call anyway */
+       ret_val = skb_cow(skb, skb_headroom(skb) + len_delta);
+       if (ret_val < 0)
+               return ret_val;
+
+       if (len_delta > 0) {
+               /* we assume that the header + opt->optlen have already been
+                * "pushed" in ip_options_build() or similar */
+               iph = ip_hdr(skb);
+               skb_push(skb, len_delta);
+               memmove((char *)iph - len_delta, iph, iph->ihl << 2);
+               skb_reset_network_header(skb);
+               iph = ip_hdr(skb);
+       } else if (len_delta < 0) {
+               iph = ip_hdr(skb);
+               memset(iph + 1, IPOPT_NOP, opt->optlen);
+       } else
+               iph = ip_hdr(skb);
+
+       if (opt->optlen > 0)
+               memset(opt, 0, sizeof(*opt));
+       opt->optlen = opt_len;
+       opt->cipso = sizeof(struct iphdr);
+       opt->is_changed = 1;
+
+       /* we have to do the following because we are being called from a
+        * netfilter hook which means the packet already has had the header
+        * fields populated and the checksum calculated - yes this means we
+        * are doing more work than needed but we do it to keep the core
+        * stack clean and tidy */
+       memcpy(iph + 1, buf, buf_len);
+       if (opt_len > buf_len)
+               memset((char *)(iph + 1) + buf_len, 0, opt_len - buf_len);
+       if (len_delta != 0) {
+               iph->ihl = 5 + (opt_len >> 2);
+               iph->tot_len = htons(skb->len);
+       }
+       ip_send_check(iph);
+
+       return 0;
+}
+
+/**
+ * cipso_v4_skbuff_delattr - Delete any CIPSO options from a packet
+ * @skb: the packet
+ *
+ * Description:
+ * Removes any and all CIPSO options from the given packet.  Returns zero on
+ * success, negative values on failure.
+ *
+ */
+int cipso_v4_skbuff_delattr(struct sk_buff *skb)
+{
+       int ret_val;
+       struct iphdr *iph;
+       struct ip_options *opt = &IPCB(skb)->opt;
+       unsigned char *cipso_ptr;
+
+       if (opt->cipso == 0)
+               return 0;
+
+       /* since we are changing the packet we should make a copy */
+       ret_val = skb_cow(skb, skb_headroom(skb));
+       if (ret_val < 0)
+               return ret_val;
+
+       /* the easiest thing to do is just replace the cipso option with noop
+        * options since we don't change the size of the packet, although we
+        * still need to recalculate the checksum */
+
+       iph = ip_hdr(skb);
+       cipso_ptr = (unsigned char *)iph + opt->cipso;
+       memset(cipso_ptr, IPOPT_NOOP, cipso_ptr[1]);
+       opt->cipso = 0;
+       opt->is_changed = 1;
+
+       ip_send_check(iph);
+
+       return 0;
+}
+
 /**
  * cipso_v4_skbuff_getattr - Get the security attributes from the CIPSO option
  * @skb: the packet
index be3f18a7a40ebbbf4f40ef90bfea8702fd4f1fae..2c88da6e7862f2b49d4d9ba17197eb9d10205fe8 100644 (file)
@@ -438,7 +438,7 @@ int ip_options_compile(struct net *net,
                                goto error;
                        }
                        opt->cipso = optptr - iph;
-                       if (cipso_v4_validate(&optptr)) {
+                       if (cipso_v4_validate(skb, &optptr)) {
                                pp_ptr = optptr;
                                goto error;
                        }
index 8af18c0a47d90b778c7f79cbfe57ac6bc5b684c9..ea750e9df65f7bdbfafcd6ae4246d6d9520707ee 100644 (file)
@@ -5,7 +5,8 @@
 #
 
 # base objects
-obj-y  := netlabel_user.o netlabel_kapi.o netlabel_domainhash.o
+obj-y  := netlabel_user.o netlabel_kapi.o
+obj-y  += netlabel_domainhash.o netlabel_addrlist.o
 
 # management objects
 obj-y  += netlabel_mgmt.o
diff --git a/net/netlabel/netlabel_addrlist.c b/net/netlabel/netlabel_addrlist.c
new file mode 100644 (file)
index 0000000..b0925a3
--- /dev/null
@@ -0,0 +1,388 @@
+/*
+ * NetLabel Network Address Lists
+ *
+ * This file contains network address list functions used to manage ordered
+ * lists of network addresses for use by the NetLabel subsystem.  The NetLabel
+ * system manages static and dynamic label mappings for network protocols such
+ * as CIPSO and RIPSO.
+ *
+ * Author: Paul Moore <paul.moore@hp.com>
+ *
+ */
+
+/*
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2008
+ *
+ * This program is free software;  you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY;  without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program;  if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/rcupdate.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/in.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <net/ip.h>
+#include <net/ipv6.h>
+#include <linux/audit.h>
+
+#include "netlabel_addrlist.h"
+
+/*
+ * Address List Functions
+ */
+
+/**
+ * netlbl_af4list_search - Search for a matching IPv4 address entry
+ * @addr: IPv4 address
+ * @head: the list head
+ *
+ * Description:
+ * Searches the IPv4 address list given by @head.  If a matching address entry
+ * is found it is returned, otherwise NULL is returned.  The caller is
+ * responsible for calling the rcu_read_[un]lock() functions.
+ *
+ */
+struct netlbl_af4list *netlbl_af4list_search(__be32 addr,
+                                            struct list_head *head)
+{
+       struct netlbl_af4list *iter;
+
+       list_for_each_entry_rcu(iter, head, list)
+               if (iter->valid && (addr & iter->mask) == iter->addr)
+                       return iter;
+
+       return NULL;
+}
+
+/**
+ * netlbl_af4list_search_exact - Search for an exact IPv4 address entry
+ * @addr: IPv4 address
+ * @mask: IPv4 address mask
+ * @head: the list head
+ *
+ * Description:
+ * Searches the IPv4 address list given by @head.  If an exact match if found
+ * it is returned, otherwise NULL is returned.  The caller is responsible for
+ * calling the rcu_read_[un]lock() functions.
+ *
+ */
+struct netlbl_af4list *netlbl_af4list_search_exact(__be32 addr,
+                                                  __be32 mask,
+                                                  struct list_head *head)
+{
+       struct netlbl_af4list *iter;
+
+       list_for_each_entry_rcu(iter, head, list)
+               if (iter->valid && iter->addr == addr && iter->mask == mask)
+                       return iter;
+
+       return NULL;
+}
+
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+/**
+ * netlbl_af6list_search - Search for a matching IPv6 address entry
+ * @addr: IPv6 address
+ * @head: the list head
+ *
+ * Description:
+ * Searches the IPv6 address list given by @head.  If a matching address entry
+ * is found it is returned, otherwise NULL is returned.  The caller is
+ * responsible for calling the rcu_read_[un]lock() functions.
+ *
+ */
+struct netlbl_af6list *netlbl_af6list_search(const struct in6_addr *addr,
+                                            struct list_head *head)
+{
+       struct netlbl_af6list *iter;
+
+       list_for_each_entry_rcu(iter, head, list)
+               if (iter->valid &&
+                   ipv6_masked_addr_cmp(&iter->addr, &iter->mask, addr) == 0)
+                       return iter;
+
+       return NULL;
+}
+
+/**
+ * netlbl_af6list_search_exact - Search for an exact IPv6 address entry
+ * @addr: IPv6 address
+ * @mask: IPv6 address mask
+ * @head: the list head
+ *
+ * Description:
+ * Searches the IPv6 address list given by @head.  If an exact match if found
+ * it is returned, otherwise NULL is returned.  The caller is responsible for
+ * calling the rcu_read_[un]lock() functions.
+ *
+ */
+struct netlbl_af6list *netlbl_af6list_search_exact(const struct in6_addr *addr,
+                                                  const struct in6_addr *mask,
+                                                  struct list_head *head)
+{
+       struct netlbl_af6list *iter;
+
+       list_for_each_entry_rcu(iter, head, list)
+               if (iter->valid &&
+                   ipv6_addr_equal(&iter->addr, addr) &&
+                   ipv6_addr_equal(&iter->mask, mask))
+                       return iter;
+
+       return NULL;
+}
+#endif /* IPv6 */
+
+/**
+ * netlbl_af4list_add - Add a new IPv4 address entry to a list
+ * @entry: address entry
+ * @head: the list head
+ *
+ * Description:
+ * Add a new address entry to the list pointed to by @head.  On success zero is
+ * returned, otherwise a negative value is returned.  The caller is responsible
+ * for calling the necessary locking functions.
+ *
+ */
+int netlbl_af4list_add(struct netlbl_af4list *entry, struct list_head *head)
+{
+       struct netlbl_af4list *iter;
+
+       iter = netlbl_af4list_search(entry->addr, head);
+       if (iter != NULL &&
+           iter->addr == entry->addr && iter->mask == entry->mask)
+               return -EEXIST;
+
+       /* in order to speed up address searches through the list (the common
+        * case) we need to keep the list in order based on the size of the
+        * address mask such that the entry with the widest mask (smallest
+        * numerical value) appears first in the list */
+       list_for_each_entry_rcu(iter, head, list)
+               if (iter->valid &&
+                   ntohl(entry->mask) > ntohl(iter->mask)) {
+                       __list_add_rcu(&entry->list,
+                                      iter->list.prev,
+                                      &iter->list);
+                       return 0;
+               }
+       list_add_tail_rcu(&entry->list, head);
+       return 0;
+}
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+/**
+ * netlbl_af6list_add - Add a new IPv6 address entry to a list
+ * @entry: address entry
+ * @head: the list head
+ *
+ * Description:
+ * Add a new address entry to the list pointed to by @head.  On success zero is
+ * returned, otherwise a negative value is returned.  The caller is responsible
+ * for calling the necessary locking functions.
+ *
+ */
+int netlbl_af6list_add(struct netlbl_af6list *entry, struct list_head *head)
+{
+       struct netlbl_af6list *iter;
+
+       iter = netlbl_af6list_search(&entry->addr, head);
+       if (iter != NULL &&
+           ipv6_addr_equal(&iter->addr, &entry->addr) &&
+           ipv6_addr_equal(&iter->mask, &entry->mask))
+               return -EEXIST;
+
+       /* in order to speed up address searches through the list (the common
+        * case) we need to keep the list in order based on the size of the
+        * address mask such that the entry with the widest mask (smallest
+        * numerical value) appears first in the list */
+       list_for_each_entry_rcu(iter, head, list)
+               if (iter->valid &&
+                   ipv6_addr_cmp(&entry->mask, &iter->mask) > 0) {
+                       __list_add_rcu(&entry->list,
+                                      iter->list.prev,
+                                      &iter->list);
+                       return 0;
+               }
+       list_add_tail_rcu(&entry->list, head);
+       return 0;
+}
+#endif /* IPv6 */
+
+/**
+ * netlbl_af4list_remove_entry - Remove an IPv4 address entry
+ * @entry: address entry
+ *
+ * Description:
+ * Remove the specified IP address entry.  The caller is responsible for
+ * calling the necessary locking functions.
+ *
+ */
+void netlbl_af4list_remove_entry(struct netlbl_af4list *entry)
+{
+       entry->valid = 0;
+       list_del_rcu(&entry->list);
+}
+
+/**
+ * netlbl_af4list_remove - Remove an IPv4 address entry
+ * @addr: IP address
+ * @mask: IP address mask
+ * @head: the list head
+ *
+ * Description:
+ * Remove an IP address entry from the list pointed to by @head.  Returns the
+ * entry on success, NULL on failure.  The caller is responsible for calling
+ * the necessary locking functions.
+ *
+ */
+struct netlbl_af4list *netlbl_af4list_remove(__be32 addr, __be32 mask,
+                                            struct list_head *head)
+{
+       struct netlbl_af4list *entry;
+
+       entry = netlbl_af4list_search(addr, head);
+       if (entry != NULL && entry->addr == addr && entry->mask == mask) {
+               netlbl_af4list_remove_entry(entry);
+               return entry;
+       }
+
+       return NULL;
+}
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+/**
+ * netlbl_af6list_remove_entry - Remove an IPv6 address entry
+ * @entry: address entry
+ *
+ * Description:
+ * Remove the specified IP address entry.  The caller is responsible for
+ * calling the necessary locking functions.
+ *
+ */
+void netlbl_af6list_remove_entry(struct netlbl_af6list *entry)
+{
+       entry->valid = 0;
+       list_del_rcu(&entry->list);
+}
+
+/**
+ * netlbl_af6list_remove - Remove an IPv6 address entry
+ * @addr: IP address
+ * @mask: IP address mask
+ * @head: the list head
+ *
+ * Description:
+ * Remove an IP address entry from the list pointed to by @head.  Returns the
+ * entry on success, NULL on failure.  The caller is responsible for calling
+ * the necessary locking functions.
+ *
+ */
+struct netlbl_af6list *netlbl_af6list_remove(const struct in6_addr *addr,
+                                            const struct in6_addr *mask,
+                                            struct list_head *head)
+{
+       struct netlbl_af6list *entry;
+
+       entry = netlbl_af6list_search(addr, head);
+       if (entry != NULL &&
+           ipv6_addr_equal(&entry->addr, addr) &&
+           ipv6_addr_equal(&entry->mask, mask)) {
+               netlbl_af6list_remove_entry(entry);
+               return entry;
+       }
+
+       return NULL;
+}
+#endif /* IPv6 */
+
+/*
+ * Audit Helper Functions
+ */
+
+/**
+ * netlbl_af4list_audit_addr - Audit an IPv4 address
+ * @audit_buf: audit buffer
+ * @src: true if source address, false if destination
+ * @dev: network interface
+ * @addr: IP address
+ * @mask: IP address mask
+ *
+ * Description:
+ * Write the IPv4 address and address mask, if necessary, to @audit_buf.
+ *
+ */
+void netlbl_af4list_audit_addr(struct audit_buffer *audit_buf,
+                                       int src, const char *dev,
+                                       __be32 addr, __be32 mask)
+{
+       u32 mask_val = ntohl(mask);
+       char *dir = (src ? "src" : "dst");
+
+       if (dev != NULL)
+               audit_log_format(audit_buf, " netif=%s", dev);
+       audit_log_format(audit_buf, " %s=" NIPQUAD_FMT, dir, NIPQUAD(addr));
+       if (mask_val != 0xffffffff) {
+               u32 mask_len = 0;
+               while (mask_val > 0) {
+                       mask_val <<= 1;
+                       mask_len++;
+               }
+               audit_log_format(audit_buf, " %s_prefixlen=%d", dir, mask_len);
+       }
+}
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+/**
+ * netlbl_af6list_audit_addr - Audit an IPv6 address
+ * @audit_buf: audit buffer
+ * @src: true if source address, false if destination
+ * @dev: network interface
+ * @addr: IP address
+ * @mask: IP address mask
+ *
+ * Description:
+ * Write the IPv6 address and address mask, if necessary, to @audit_buf.
+ *
+ */
+void netlbl_af6list_audit_addr(struct audit_buffer *audit_buf,
+                                int src,
+                                const char *dev,
+                                const struct in6_addr *addr,
+                                const struct in6_addr *mask)
+{
+       char *dir = (src ? "src" : "dst");
+
+       if (dev != NULL)
+               audit_log_format(audit_buf, " netif=%s", dev);
+       audit_log_format(audit_buf, " %s=" NIP6_FMT, dir, NIP6(*addr));
+       if (ntohl(mask->s6_addr32[3]) != 0xffffffff) {
+               u32 mask_len = 0;
+               u32 mask_val;
+               int iter = -1;
+               while (ntohl(mask->s6_addr32[++iter]) == 0xffffffff)
+                       mask_len += 32;
+               mask_val = ntohl(mask->s6_addr32[iter]);
+               while (mask_val > 0) {
+                       mask_val <<= 1;
+                       mask_len++;
+               }
+               audit_log_format(audit_buf, " %s_prefixlen=%d", dir, mask_len);
+       }
+}
+#endif /* IPv6 */
diff --git a/net/netlabel/netlabel_addrlist.h b/net/netlabel/netlabel_addrlist.h
new file mode 100644 (file)
index 0000000..0242bea
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+ * NetLabel Network Address Lists
+ *
+ * This file contains network address list functions used to manage ordered
+ * lists of network addresses for use by the NetLabel subsystem.  The NetLabel
+ * system manages static and dynamic label mappings for network protocols such
+ * as CIPSO and RIPSO.
+ *
+ * Author: Paul Moore <paul.moore@hp.com>
+ *
+ */
+
+/*
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2008
+ *
+ * This program is free software;  you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY;  without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program;  if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef _NETLABEL_ADDRLIST_H
+#define _NETLABEL_ADDRLIST_H
+
+#include <linux/types.h>
+#include <linux/rcupdate.h>
+#include <linux/list.h>
+#include <linux/in6.h>
+#include <linux/audit.h>
+
+/**
+ * struct netlbl_af4list - NetLabel IPv4 address list
+ * @addr: IPv4 address
+ * @mask: IPv4 address mask
+ * @valid: valid flag
+ * @list: list structure, used internally
+ */
+struct netlbl_af4list {
+       __be32 addr;
+       __be32 mask;
+
+       u32 valid;
+       struct list_head list;
+};
+
+/**
+ * struct netlbl_af6list - NetLabel IPv6 address list
+ * @addr: IPv6 address
+ * @mask: IPv6 address mask
+ * @valid: valid flag
+ * @list: list structure, used internally
+ */
+struct netlbl_af6list {
+       struct in6_addr addr;
+       struct in6_addr mask;
+
+       u32 valid;
+       struct list_head list;
+};
+
+#define __af4list_entry(ptr) container_of(ptr, struct netlbl_af4list, list)
+
+static inline struct netlbl_af4list *__af4list_valid(struct list_head *s,
+                                                    struct list_head *h)
+{
+       struct list_head *i = s;
+       struct netlbl_af4list *n = __af4list_entry(s);
+       while (i != h && !n->valid) {
+               i = i->next;
+               n = __af4list_entry(i);
+       }
+       return n;
+}
+
+static inline struct netlbl_af4list *__af4list_valid_rcu(struct list_head *s,
+                                                        struct list_head *h)
+{
+       struct list_head *i = s;
+       struct netlbl_af4list *n = __af4list_entry(s);
+       while (i != h && !n->valid) {
+               i = rcu_dereference(i->next);
+               n = __af4list_entry(i);
+       }
+       return n;
+}
+
+#define netlbl_af4list_foreach(iter, head)                             \
+       for (iter = __af4list_valid((head)->next, head);                \
+            prefetch(iter->list.next), &iter->list != (head);          \
+            iter = __af4list_valid(iter->list.next, head))
+
+#define netlbl_af4list_foreach_rcu(iter, head)                         \
+       for (iter = __af4list_valid_rcu((head)->next, head);            \
+            prefetch(iter->list.next), &iter->list != (head);          \
+            iter = __af4list_valid_rcu(iter->list.next, head))
+
+#define netlbl_af4list_foreach_safe(iter, tmp, head)                   \
+       for (iter = __af4list_valid((head)->next, head),                \
+                    tmp = __af4list_valid(iter->list.next, head);      \
+            &iter->list != (head);                                     \
+            iter = tmp, tmp = __af4list_valid(iter->list.next, head))
+
+int netlbl_af4list_add(struct netlbl_af4list *entry,
+                      struct list_head *head);
+struct netlbl_af4list *netlbl_af4list_remove(__be32 addr, __be32 mask,
+                                            struct list_head *head);
+void netlbl_af4list_remove_entry(struct netlbl_af4list *entry);
+struct netlbl_af4list *netlbl_af4list_search(__be32 addr,
+                                            struct list_head *head);
+struct netlbl_af4list *netlbl_af4list_search_exact(__be32 addr,
+                                                  __be32 mask,
+                                                  struct list_head *head);
+void netlbl_af4list_audit_addr(struct audit_buffer *audit_buf,
+                              int src, const char *dev,
+                              __be32 addr, __be32 mask);
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+
+#define __af6list_entry(ptr) container_of(ptr, struct netlbl_af6list, list)
+
+static inline struct netlbl_af6list *__af6list_valid(struct list_head *s,
+                                                    struct list_head *h)
+{
+       struct list_head *i = s;
+       struct netlbl_af6list *n = __af6list_entry(s);
+       while (i != h && !n->valid) {
+               i = i->next;
+               n = __af6list_entry(i);
+       }
+       return n;
+}
+
+static inline struct netlbl_af6list *__af6list_valid_rcu(struct list_head *s,
+                                                        struct list_head *h)
+{
+       struct list_head *i = s;
+       struct netlbl_af6list *n = __af6list_entry(s);
+       while (i != h && !n->valid) {
+               i = rcu_dereference(i->next);
+               n = __af6list_entry(i);
+       }
+       return n;
+}
+
+#define netlbl_af6list_foreach(iter, head)                             \
+       for (iter = __af6list_valid((head)->next, head);                \
+            prefetch(iter->list.next), &iter->list != (head);          \
+            iter = __af6list_valid(iter->list.next, head))
+
+#define netlbl_af6list_foreach_rcu(iter, head)                         \
+       for (iter = __af6list_valid_rcu((head)->next, head);            \
+            prefetch(iter->list.next), &iter->list != (head);          \
+            iter = __af6list_valid_rcu(iter->list.next, head))
+
+#define netlbl_af6list_foreach_safe(iter, tmp, head)                   \
+       for (iter = __af6list_valid((head)->next, head),                \
+                    tmp = __af6list_valid(iter->list.next, head);      \
+            &iter->list != (head);                                     \
+            iter = tmp, tmp = __af6list_valid(iter->list.next, head))
+
+int netlbl_af6list_add(struct netlbl_af6list *entry,
+                      struct list_head *head);
+struct netlbl_af6list *netlbl_af6list_remove(const struct in6_addr *addr,
+                                            const struct in6_addr *mask,
+                                            struct list_head *head);
+void netlbl_af6list_remove_entry(struct netlbl_af6list *entry);
+struct netlbl_af6list *netlbl_af6list_search(const struct in6_addr *addr,
+                                            struct list_head *head);
+struct netlbl_af6list *netlbl_af6list_search_exact(const struct in6_addr *addr,
+                                                  const struct in6_addr *mask,
+                                                  struct list_head *head);
+void netlbl_af6list_audit_addr(struct audit_buffer *audit_buf,
+                              int src,
+                              const char *dev,
+                              const struct in6_addr *addr,
+                              const struct in6_addr *mask);
+#endif /* IPV6 */
+
+#endif
index 0aec318bf0ef17aed66c4ec10881846403f0d9b4..fff32b70efa9d9d0e1b71e7ef56dce87ee83736a 100644 (file)
@@ -43,6 +43,7 @@
 #include "netlabel_user.h"
 #include "netlabel_cipso_v4.h"
 #include "netlabel_mgmt.h"
+#include "netlabel_domainhash.h"
 
 /* Argument struct for cipso_v4_doi_walk() */
 struct netlbl_cipsov4_doiwalk_arg {
@@ -51,6 +52,12 @@ struct netlbl_cipsov4_doiwalk_arg {
        u32 seq;
 };
 
+/* Argument struct for netlbl_domhsh_walk() */
+struct netlbl_domhsh_walk_arg {
+       struct netlbl_audit *audit_info;
+       u32 doi;
+};
+
 /* NetLabel Generic NETLINK CIPSOv4 family */
 static struct genl_family netlbl_cipsov4_gnl_family = {
        .id = GENL_ID_GENERATE,
@@ -80,32 +87,6 @@ static const struct nla_policy netlbl_cipsov4_genl_policy[NLBL_CIPSOV4_A_MAX + 1
  * Helper Functions
  */
 
-/**
- * netlbl_cipsov4_doi_free - Frees a CIPSO V4 DOI definition
- * @entry: the entry's RCU field
- *
- * Description:
- * This function is designed to be used as a callback to the call_rcu()
- * function so that the memory allocated to the DOI definition can be released
- * safely.
- *
- */
-void netlbl_cipsov4_doi_free(struct rcu_head *entry)
-{
-       struct cipso_v4_doi *ptr;
-
-       ptr = container_of(entry, struct cipso_v4_doi, rcu);
-       switch (ptr->type) {
-       case CIPSO_V4_MAP_STD:
-               kfree(ptr->map.std->lvl.cipso);
-               kfree(ptr->map.std->lvl.local);
-               kfree(ptr->map.std->cat.cipso);
-               kfree(ptr->map.std->cat.local);
-               break;
-       }
-       kfree(ptr);
-}
-
 /**
  * netlbl_cipsov4_add_common - Parse the common sections of a ADD message
  * @info: the Generic NETLINK info block
@@ -151,9 +132,9 @@ static int netlbl_cipsov4_add_common(struct genl_info *info,
  * @info: the Generic NETLINK info block
  *
  * Description:
- * Create a new CIPSO_V4_MAP_STD DOI definition based on the given ADD message
- * and add it to the CIPSO V4 engine.  Return zero on success and non-zero on
- * error.
+ * Create a new CIPSO_V4_MAP_TRANS DOI definition based on the given ADD
+ * message and add it to the CIPSO V4 engine.  Return zero on success and
+ * non-zero on error.
  *
  */
 static int netlbl_cipsov4_add_std(struct genl_info *info)
@@ -183,7 +164,7 @@ static int netlbl_cipsov4_add_std(struct genl_info *info)
                ret_val = -ENOMEM;
                goto add_std_failure;
        }
-       doi_def->type = CIPSO_V4_MAP_STD;
+       doi_def->type = CIPSO_V4_MAP_TRANS;
 
        ret_val = netlbl_cipsov4_add_common(info, doi_def);
        if (ret_val != 0)
@@ -342,7 +323,7 @@ static int netlbl_cipsov4_add_std(struct genl_info *info)
 
 add_std_failure:
        if (doi_def)
-               netlbl_cipsov4_doi_free(&doi_def->rcu);
+               cipso_v4_doi_free(doi_def);
        return ret_val;
 }
 
@@ -379,7 +360,44 @@ static int netlbl_cipsov4_add_pass(struct genl_info *info)
        return 0;
 
 add_pass_failure:
-       netlbl_cipsov4_doi_free(&doi_def->rcu);
+       cipso_v4_doi_free(doi_def);
+       return ret_val;
+}
+
+/**
+ * netlbl_cipsov4_add_local - Adds a CIPSO V4 DOI definition
+ * @info: the Generic NETLINK info block
+ *
+ * Description:
+ * Create a new CIPSO_V4_MAP_LOCAL DOI definition based on the given ADD
+ * message and add it to the CIPSO V4 engine.  Return zero on success and
+ * non-zero on error.
+ *
+ */
+static int netlbl_cipsov4_add_local(struct genl_info *info)
+{
+       int ret_val;
+       struct cipso_v4_doi *doi_def = NULL;
+
+       if (!info->attrs[NLBL_CIPSOV4_A_TAGLST])
+               return -EINVAL;
+
+       doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL);
+       if (doi_def == NULL)
+               return -ENOMEM;
+       doi_def->type = CIPSO_V4_MAP_LOCAL;
+
+       ret_val = netlbl_cipsov4_add_common(info, doi_def);
+       if (ret_val != 0)
+               goto add_local_failure;
+
+       ret_val = cipso_v4_doi_add(doi_def);
+       if (ret_val != 0)
+               goto add_local_failure;
+       return 0;
+
+add_local_failure:
+       cipso_v4_doi_free(doi_def);
        return ret_val;
 }
 
@@ -412,14 +430,18 @@ static int netlbl_cipsov4_add(struct sk_buff *skb, struct genl_info *info)
 
        type = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_MTYPE]);
        switch (type) {
-       case CIPSO_V4_MAP_STD:
-               type_str = "std";
+       case CIPSO_V4_MAP_TRANS:
+               type_str = "trans";
                ret_val = netlbl_cipsov4_add_std(info);
                break;
        case CIPSO_V4_MAP_PASS:
                type_str = "pass";
                ret_val = netlbl_cipsov4_add_pass(info);
                break;
+       case CIPSO_V4_MAP_LOCAL:
+               type_str = "local";
+               ret_val = netlbl_cipsov4_add_local(info);
+               break;
        }
        if (ret_val == 0)
                atomic_inc(&netlabel_mgmt_protocount);
@@ -491,7 +513,7 @@ list_start:
        doi_def = cipso_v4_doi_getdef(doi);
        if (doi_def == NULL) {
                ret_val = -EINVAL;
-               goto list_failure;
+               goto list_failure_lock;
        }
 
        ret_val = nla_put_u32(ans_skb, NLBL_CIPSOV4_A_MTYPE, doi_def->type);
@@ -516,7 +538,7 @@ list_start:
        nla_nest_end(ans_skb, nla_a);
 
        switch (doi_def->type) {
-       case CIPSO_V4_MAP_STD:
+       case CIPSO_V4_MAP_TRANS:
                nla_a = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_MLSLVLLST);
                if (nla_a == NULL) {
                        ret_val = -ENOMEM;
@@ -655,7 +677,7 @@ static int netlbl_cipsov4_listall(struct sk_buff *skb,
                                  struct netlink_callback *cb)
 {
        struct netlbl_cipsov4_doiwalk_arg cb_arg;
-       int doi_skip = cb->args[0];
+       u32 doi_skip = cb->args[0];
 
        cb_arg.nl_cb = cb;
        cb_arg.skb = skb;
@@ -667,6 +689,29 @@ static int netlbl_cipsov4_listall(struct sk_buff *skb,
        return skb->len;
 }
 
+/**
+ * netlbl_cipsov4_remove_cb - netlbl_cipsov4_remove() callback for REMOVE
+ * @entry: LSM domain mapping entry
+ * @arg: the netlbl_domhsh_walk_arg structure
+ *
+ * Description:
+ * This function is intended for use by netlbl_cipsov4_remove() as the callback
+ * for the netlbl_domhsh_walk() function; it removes LSM domain map entries
+ * which are associated with the CIPSO DOI specified in @arg.  Returns zero on
+ * success, negative values on failure.
+ *
+ */
+static int netlbl_cipsov4_remove_cb(struct netlbl_dom_map *entry, void *arg)
+{
+       struct netlbl_domhsh_walk_arg *cb_arg = arg;
+
+       if (entry->type == NETLBL_NLTYPE_CIPSOV4 &&
+           entry->type_def.cipsov4->doi == cb_arg->doi)
+               return netlbl_domhsh_remove_entry(entry, cb_arg->audit_info);
+
+       return 0;
+}
+
 /**
  * netlbl_cipsov4_remove - Handle a REMOVE message
  * @skb: the NETLINK buffer
@@ -681,8 +726,11 @@ static int netlbl_cipsov4_remove(struct sk_buff *skb, struct genl_info *info)
 {
        int ret_val = -EINVAL;
        u32 doi = 0;
+       struct netlbl_domhsh_walk_arg cb_arg;
        struct audit_buffer *audit_buf;
        struct netlbl_audit audit_info;
+       u32 skip_bkt = 0;
+       u32 skip_chain = 0;
 
        if (!info->attrs[NLBL_CIPSOV4_A_DOI])
                return -EINVAL;
@@ -690,11 +738,15 @@ static int netlbl_cipsov4_remove(struct sk_buff *skb, struct genl_info *info)
        doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
        netlbl_netlink_auditinfo(skb, &audit_info);
 
-       ret_val = cipso_v4_doi_remove(doi,
-                                     &audit_info,
-                                     netlbl_cipsov4_doi_free);
-       if (ret_val == 0)
-               atomic_dec(&netlabel_mgmt_protocount);
+       cb_arg.doi = doi;
+       cb_arg.audit_info = &audit_info;
+       ret_val = netlbl_domhsh_walk(&skip_bkt, &skip_chain,
+                                    netlbl_cipsov4_remove_cb, &cb_arg);
+       if (ret_val == 0 || ret_val == -ENOENT) {
+               ret_val = cipso_v4_doi_remove(doi, &audit_info);
+               if (ret_val == 0)
+                       atomic_dec(&netlabel_mgmt_protocount);
+       }
 
        audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_DEL,
                                              &audit_info);
index 220cb9d06b496d315d30c1041a03525421b4a9e2..c8a4079261f04a88147695554865bab3765ce3bd 100644 (file)
  *     NLBL_CIPSOV4_A_MTYPE
  *     NLBL_CIPSOV4_A_TAGLST
  *
- *   If using CIPSO_V4_MAP_STD the following attributes are required:
+ *   If using CIPSO_V4_MAP_TRANS the following attributes are required:
  *
  *     NLBL_CIPSOV4_A_MLSLVLLST
  *     NLBL_CIPSOV4_A_MLSCATLST
  *
- *   If using CIPSO_V4_MAP_PASS no additional attributes are required.
+ *   If using CIPSO_V4_MAP_PASS or CIPSO_V4_MAP_LOCAL no additional attributes
+ *   are required.
  *
  * o REMOVE:
  *   Sent by an application to remove a specific DOI mapping table from the
  *     NLBL_CIPSOV4_A_MTYPE
  *     NLBL_CIPSOV4_A_TAGLST
  *
- *   If using CIPSO_V4_MAP_STD the following attributes are required:
+ *   If using CIPSO_V4_MAP_TRANS the following attributes are required:
  *
  *     NLBL_CIPSOV4_A_MLSLVLLST
  *     NLBL_CIPSOV4_A_MLSCATLST
  *
- *   If using CIPSO_V4_MAP_PASS no additional attributes are required.
+ *   If using CIPSO_V4_MAP_PASS or CIPSO_V4_MAP_LOCAL no additional attributes
+ *   are required.
  *
  * o LISTALL:
  *   This message is sent by an application to list the valid DOIs on the
index 643c032a3a57dd50a89a92d3536e52ad03c5d01a..5fadf10e5ddfe39cf19eb760f2b404d93d8c53b3 100644 (file)
@@ -11,7 +11,7 @@
  */
 
 /*
- * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008
  *
  * 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
@@ -40,6 +40,7 @@
 #include <asm/bug.h>
 
 #include "netlabel_mgmt.h"
+#include "netlabel_addrlist.h"
 #include "netlabel_domainhash.h"
 #include "netlabel_user.h"
 
@@ -72,8 +73,28 @@ static struct netlbl_dom_map *netlbl_domhsh_def = NULL;
 static void netlbl_domhsh_free_entry(struct rcu_head *entry)
 {
        struct netlbl_dom_map *ptr;
+       struct netlbl_af4list *iter4;
+       struct netlbl_af4list *tmp4;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       struct netlbl_af6list *iter6;
+       struct netlbl_af6list *tmp6;
+#endif /* IPv6 */
 
        ptr = container_of(entry, struct netlbl_dom_map, rcu);
+       if (ptr->type == NETLBL_NLTYPE_ADDRSELECT) {
+               netlbl_af4list_foreach_safe(iter4, tmp4,
+                                           &ptr->type_def.addrsel->list4) {
+                       netlbl_af4list_remove_entry(iter4);
+                       kfree(netlbl_domhsh_addr4_entry(iter4));
+               }
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+               netlbl_af6list_foreach_safe(iter6, tmp6,
+                                           &ptr->type_def.addrsel->list6) {
+                       netlbl_af6list_remove_entry(iter6);
+                       kfree(netlbl_domhsh_addr6_entry(iter6));
+               }
+#endif /* IPv6 */
+       }
        kfree(ptr->domain);
        kfree(ptr);
 }
@@ -115,13 +136,13 @@ static u32 netlbl_domhsh_hash(const char *key)
 static struct netlbl_dom_map *netlbl_domhsh_search(const char *domain)
 {
        u32 bkt;
+       struct list_head *bkt_list;
        struct netlbl_dom_map *iter;
 
        if (domain != NULL) {
                bkt = netlbl_domhsh_hash(domain);
-               list_for_each_entry_rcu(iter,
-                                    &rcu_dereference(netlbl_domhsh)->tbl[bkt],
-                                    list)
+               bkt_list = &rcu_dereference(netlbl_domhsh)->tbl[bkt];
+               list_for_each_entry_rcu(iter, bkt_list, list)
                        if (iter->valid && strcmp(iter->domain, domain) == 0)
                                return iter;
        }
@@ -156,6 +177,69 @@ static struct netlbl_dom_map *netlbl_domhsh_search_def(const char *domain)
        return entry;
 }
 
+/**
+ * netlbl_domhsh_audit_add - Generate an audit entry for an add event
+ * @entry: the entry being added
+ * @addr4: the IPv4 address information
+ * @addr6: the IPv6 address information
+ * @result: the result code
+ * @audit_info: NetLabel audit information
+ *
+ * Description:
+ * Generate an audit record for adding a new NetLabel/LSM mapping entry with
+ * the given information.  Caller is responsibile for holding the necessary
+ * locks.
+ *
+ */
+static void netlbl_domhsh_audit_add(struct netlbl_dom_map *entry,
+                                   struct netlbl_af4list *addr4,
+                                   struct netlbl_af6list *addr6,
+                                   int result,
+                                   struct netlbl_audit *audit_info)
+{
+       struct audit_buffer *audit_buf;
+       struct cipso_v4_doi *cipsov4 = NULL;
+       u32 type;
+
+       audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_ADD, audit_info);
+       if (audit_buf != NULL) {
+               audit_log_format(audit_buf, " nlbl_domain=%s",
+                                entry->domain ? entry->domain : "(default)");
+               if (addr4 != NULL) {
+                       struct netlbl_domaddr4_map *map4;
+                       map4 = netlbl_domhsh_addr4_entry(addr4);
+                       type = map4->type;
+                       cipsov4 = map4->type_def.cipsov4;
+                       netlbl_af4list_audit_addr(audit_buf, 0, NULL,
+                                                 addr4->addr, addr4->mask);
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+               } else if (addr6 != NULL) {
+                       struct netlbl_domaddr6_map *map6;
+                       map6 = netlbl_domhsh_addr6_entry(addr6);
+                       type = map6->type;
+                       netlbl_af6list_audit_addr(audit_buf, 0, NULL,
+                                                 &addr6->addr, &addr6->mask);
+#endif /* IPv6 */
+               } else {
+                       type = entry->type;
+                       cipsov4 = entry->type_def.cipsov4;
+               }
+               switch (type) {
+               case NETLBL_NLTYPE_UNLABELED:
+                       audit_log_format(audit_buf, " nlbl_protocol=unlbl");
+                       break;
+               case NETLBL_NLTYPE_CIPSOV4:
+                       BUG_ON(cipsov4 == NULL);
+                       audit_log_format(audit_buf,
+                                        " nlbl_protocol=cipsov4 cipso_doi=%u",
+                                        cipsov4->doi);
+                       break;
+               }
+               audit_log_format(audit_buf, " res=%u", result == 0 ? 1 : 0);
+               audit_log_end(audit_buf);
+       }
+}
+
 /*
  * Domain Hash Table Functions
  */
@@ -213,74 +297,106 @@ int __init netlbl_domhsh_init(u32 size)
 int netlbl_domhsh_add(struct netlbl_dom_map *entry,
                      struct netlbl_audit *audit_info)
 {
-       int ret_val;
-       u32 bkt;
-       struct audit_buffer *audit_buf;
-
-       switch (entry->type) {
-       case NETLBL_NLTYPE_UNLABELED:
-               ret_val = 0;
-               break;
-       case NETLBL_NLTYPE_CIPSOV4:
-               ret_val = cipso_v4_doi_domhsh_add(entry->type_def.cipsov4,
-                                                 entry->domain);
-               break;
-       default:
-               return -EINVAL;
-       }
-       if (ret_val != 0)
-               return ret_val;
-
-       entry->valid = 1;
-       INIT_RCU_HEAD(&entry->rcu);
+       int ret_val = 0;
+       struct netlbl_dom_map *entry_old;
+       struct netlbl_af4list *iter4;
+       struct netlbl_af4list *tmp4;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       struct netlbl_af6list *iter6;
+       struct netlbl_af6list *tmp6;
+#endif /* IPv6 */
 
        rcu_read_lock();
+
        spin_lock(&netlbl_domhsh_lock);
-       if (entry->domain != NULL) {
-               bkt = netlbl_domhsh_hash(entry->domain);
-               if (netlbl_domhsh_search(entry->domain) == NULL)
+       if (entry->domain != NULL)
+               entry_old = netlbl_domhsh_search(entry->domain);
+       else
+               entry_old = netlbl_domhsh_search_def(entry->domain);
+       if (entry_old == NULL) {
+               entry->valid = 1;
+               INIT_RCU_HEAD(&entry->rcu);
+
+               if (entry->domain != NULL) {
+                       u32 bkt = netlbl_domhsh_hash(entry->domain);
                        list_add_tail_rcu(&entry->list,
                                    &rcu_dereference(netlbl_domhsh)->tbl[bkt]);
-               else
-                       ret_val = -EEXIST;
-       } else {
-               INIT_LIST_HEAD(&entry->list);
-               if (rcu_dereference(netlbl_domhsh_def) == NULL)
+               } else {
+                       INIT_LIST_HEAD(&entry->list);
                        rcu_assign_pointer(netlbl_domhsh_def, entry);
-               else
-                       ret_val = -EEXIST;
-       }
-       spin_unlock(&netlbl_domhsh_lock);
-       audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_ADD, audit_info);
-       if (audit_buf != NULL) {
-               audit_log_format(audit_buf,
-                                " nlbl_domain=%s",
-                                entry->domain ? entry->domain : "(default)");
-               switch (entry->type) {
-               case NETLBL_NLTYPE_UNLABELED:
-                       audit_log_format(audit_buf, " nlbl_protocol=unlbl");
-                       break;
-               case NETLBL_NLTYPE_CIPSOV4:
-                       audit_log_format(audit_buf,
-                                        " nlbl_protocol=cipsov4 cipso_doi=%u",
-                                        entry->type_def.cipsov4->doi);
-                       break;
                }
-               audit_log_format(audit_buf, " res=%u", ret_val == 0 ? 1 : 0);
-               audit_log_end(audit_buf);
-       }
-       rcu_read_unlock();
 
-       if (ret_val != 0) {
-               switch (entry->type) {
-               case NETLBL_NLTYPE_CIPSOV4:
-                       if (cipso_v4_doi_domhsh_remove(entry->type_def.cipsov4,
-                                                      entry->domain) != 0)
-                               BUG();
-                       break;
+               if (entry->type == NETLBL_NLTYPE_ADDRSELECT) {
+                       netlbl_af4list_foreach_rcu(iter4,
+                                              &entry->type_def.addrsel->list4)
+                               netlbl_domhsh_audit_add(entry, iter4, NULL,
+                                                       ret_val, audit_info);
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+                       netlbl_af6list_foreach_rcu(iter6,
+                                              &entry->type_def.addrsel->list6)
+                               netlbl_domhsh_audit_add(entry, NULL, iter6,
+                                                       ret_val, audit_info);
+#endif /* IPv6 */
+               } else
+                       netlbl_domhsh_audit_add(entry, NULL, NULL,
+                                               ret_val, audit_info);
+       } else if (entry_old->type == NETLBL_NLTYPE_ADDRSELECT &&
+                  entry->type == NETLBL_NLTYPE_ADDRSELECT) {
+               struct list_head *old_list4;
+               struct list_head *old_list6;
+
+               old_list4 = &entry_old->type_def.addrsel->list4;
+               old_list6 = &entry_old->type_def.addrsel->list6;
+
+               /* we only allow the addition of address selectors if all of
+                * the selectors do not exist in the existing domain map */
+               netlbl_af4list_foreach_rcu(iter4,
+                                          &entry->type_def.addrsel->list4)
+                       if (netlbl_af4list_search_exact(iter4->addr,
+                                                       iter4->mask,
+                                                       old_list4)) {
+                               ret_val = -EEXIST;
+                               goto add_return;
+                       }
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+               netlbl_af6list_foreach_rcu(iter6,
+                                          &entry->type_def.addrsel->list6)
+                       if (netlbl_af6list_search_exact(&iter6->addr,
+                                                       &iter6->mask,
+                                                       old_list6)) {
+                               ret_val = -EEXIST;
+                               goto add_return;
+                       }
+#endif /* IPv6 */
+
+               netlbl_af4list_foreach_safe(iter4, tmp4,
+                                           &entry->type_def.addrsel->list4) {
+                       netlbl_af4list_remove_entry(iter4);
+                       iter4->valid = 1;
+                       ret_val = netlbl_af4list_add(iter4, old_list4);
+                       netlbl_domhsh_audit_add(entry_old, iter4, NULL,
+                                               ret_val, audit_info);
+                       if (ret_val != 0)
+                               goto add_return;
                }
-       }
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+               netlbl_af6list_foreach_safe(iter6, tmp6,
+                                           &entry->type_def.addrsel->list6) {
+                       netlbl_af6list_remove_entry(iter6);
+                       iter6->valid = 1;
+                       ret_val = netlbl_af6list_add(iter6, old_list6);
+                       netlbl_domhsh_audit_add(entry_old, NULL, iter6,
+                                               ret_val, audit_info);
+                       if (ret_val != 0)
+                               goto add_return;
+               }
+#endif /* IPv6 */
+       } else
+               ret_val = -EINVAL;
 
+add_return:
+       spin_unlock(&netlbl_domhsh_lock);
+       rcu_read_unlock();
        return ret_val;
 }
 
@@ -302,35 +418,26 @@ int netlbl_domhsh_add_default(struct netlbl_dom_map *entry,
 }
 
 /**
- * netlbl_domhsh_remove - Removes an entry from the domain hash table
- * @domain: the domain to remove
+ * netlbl_domhsh_remove_entry - Removes a given entry from the domain table
+ * @entry: the entry to remove
  * @audit_info: NetLabel audit information
  *
  * Description:
  * Removes an entry from the domain hash table and handles any updates to the
- * lower level protocol handler (i.e. CIPSO).  Returns zero on success,
- * negative on failure.
+ * lower level protocol handler (i.e. CIPSO).  Caller is responsible for
+ * ensuring that the RCU read lock is held.  Returns zero on success, negative
+ * on failure.
  *
  */
-int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info)
+int netlbl_domhsh_remove_entry(struct netlbl_dom_map *entry,
+                              struct netlbl_audit *audit_info)
 {
-       int ret_val = -ENOENT;
-       struct netlbl_dom_map *entry;
+       int ret_val = 0;
        struct audit_buffer *audit_buf;
 
-       rcu_read_lock();
-       if (domain)
-               entry = netlbl_domhsh_search(domain);
-       else
-               entry = netlbl_domhsh_search_def(domain);
        if (entry == NULL)
-               goto remove_return;
-       switch (entry->type) {
-       case NETLBL_NLTYPE_CIPSOV4:
-               cipso_v4_doi_domhsh_remove(entry->type_def.cipsov4,
-                                          entry->domain);
-               break;
-       }
+               return -ENOENT;
+
        spin_lock(&netlbl_domhsh_lock);
        if (entry->valid) {
                entry->valid = 0;
@@ -338,8 +445,8 @@ int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info)
                        list_del_rcu(&entry->list);
                else
                        rcu_assign_pointer(netlbl_domhsh_def, NULL);
-               ret_val = 0;
-       }
+       } else
+               ret_val = -ENOENT;
        spin_unlock(&netlbl_domhsh_lock);
 
        audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_DEL, audit_info);
@@ -351,10 +458,54 @@ int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info)
                audit_log_end(audit_buf);
        }
 
-remove_return:
-       rcu_read_unlock();
-       if (ret_val == 0)
+       if (ret_val == 0) {
+               struct netlbl_af4list *iter4;
+               struct netlbl_domaddr4_map *map4;
+
+               switch (entry->type) {
+               case NETLBL_NLTYPE_ADDRSELECT:
+                       netlbl_af4list_foreach_rcu(iter4,
+                                            &entry->type_def.addrsel->list4) {
+                               map4 = netlbl_domhsh_addr4_entry(iter4);
+                               cipso_v4_doi_putdef(map4->type_def.cipsov4);
+                       }
+                       /* no need to check the IPv6 list since we currently
+                        * support only unlabeled protocols for IPv6 */
+                       break;
+               case NETLBL_NLTYPE_CIPSOV4:
+                       cipso_v4_doi_putdef(entry->type_def.cipsov4);
+                       break;
+               }
                call_rcu(&entry->rcu, netlbl_domhsh_free_entry);
+       }
+
+       return ret_val;
+}
+
+/**
+ * netlbl_domhsh_remove - Removes an entry from the domain hash table
+ * @domain: the domain to remove
+ * @audit_info: NetLabel audit information
+ *
+ * Description:
+ * Removes an entry from the domain hash table and handles any updates to the
+ * lower level protocol handler (i.e. CIPSO).  Returns zero on success,
+ * negative on failure.
+ *
+ */
+int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info)
+{
+       int ret_val;
+       struct netlbl_dom_map *entry;
+
+       rcu_read_lock();
+       if (domain)
+               entry = netlbl_domhsh_search(domain);
+       else
+               entry = netlbl_domhsh_search_def(domain);
+       ret_val = netlbl_domhsh_remove_entry(entry, audit_info);
+       rcu_read_unlock();
+
        return ret_val;
 }
 
@@ -388,6 +539,70 @@ struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain)
        return netlbl_domhsh_search_def(domain);
 }
 
+/**
+ * netlbl_domhsh_getentry_af4 - Get an entry from the domain hash table
+ * @domain: the domain name to search for
+ * @addr: the IP address to search for
+ *
+ * Description:
+ * Look through the domain hash table searching for an entry to match @domain
+ * and @addr, return a pointer to a copy of the entry or NULL.  The caller is
+ * responsible for ensuring that rcu_read_[un]lock() is called.
+ *
+ */
+struct netlbl_domaddr4_map *netlbl_domhsh_getentry_af4(const char *domain,
+                                                      __be32 addr)
+{
+       struct netlbl_dom_map *dom_iter;
+       struct netlbl_af4list *addr_iter;
+
+       dom_iter = netlbl_domhsh_search_def(domain);
+       if (dom_iter == NULL)
+               return NULL;
+       if (dom_iter->type != NETLBL_NLTYPE_ADDRSELECT)
+               return NULL;
+
+       addr_iter = netlbl_af4list_search(addr,
+                                         &dom_iter->type_def.addrsel->list4);
+       if (addr_iter == NULL)
+               return NULL;
+
+       return netlbl_domhsh_addr4_entry(addr_iter);
+}
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+/**
+ * netlbl_domhsh_getentry_af6 - Get an entry from the domain hash table
+ * @domain: the domain name to search for
+ * @addr: the IP address to search for
+ *
+ * Description:
+ * Look through the domain hash table searching for an entry to match @domain
+ * and @addr, return a pointer to a copy of the entry or NULL.  The caller is
+ * responsible for ensuring that rcu_read_[un]lock() is called.
+ *
+ */
+struct netlbl_domaddr6_map *netlbl_domhsh_getentry_af6(const char *domain,
+                                                  const struct in6_addr *addr)
+{
+       struct netlbl_dom_map *dom_iter;
+       struct netlbl_af6list *addr_iter;
+
+       dom_iter = netlbl_domhsh_search_def(domain);
+       if (dom_iter == NULL)
+               return NULL;
+       if (dom_iter->type != NETLBL_NLTYPE_ADDRSELECT)
+               return NULL;
+
+       addr_iter = netlbl_af6list_search(addr,
+                                         &dom_iter->type_def.addrsel->list6);
+       if (addr_iter == NULL)
+               return NULL;
+
+       return netlbl_domhsh_addr6_entry(addr_iter);
+}
+#endif /* IPv6 */
+
 /**
  * netlbl_domhsh_walk - Iterate through the domain mapping hash table
  * @skip_bkt: the number of buckets to skip at the start
@@ -410,6 +625,7 @@ int netlbl_domhsh_walk(u32 *skip_bkt,
 {
        int ret_val = -ENOENT;
        u32 iter_bkt;
+       struct list_head *iter_list;
        struct netlbl_dom_map *iter_entry;
        u32 chain_cnt = 0;
 
@@ -417,9 +633,8 @@ int netlbl_domhsh_walk(u32 *skip_bkt,
        for (iter_bkt = *skip_bkt;
             iter_bkt < rcu_dereference(netlbl_domhsh)->size;
             iter_bkt++, chain_cnt = 0) {
-               list_for_each_entry_rcu(iter_entry,
-                               &rcu_dereference(netlbl_domhsh)->tbl[iter_bkt],
-                               list)
+               iter_list = &rcu_dereference(netlbl_domhsh)->tbl[iter_bkt];
+               list_for_each_entry_rcu(iter_entry, iter_list, list)
                        if (iter_entry->valid) {
                                if (chain_cnt++ < *skip_chain)
                                        continue;
index 8220990ceb967a0480421e82c465490fab3983b8..bfcb6763a1a15fac8edbcfe51045e706a9b00149 100644 (file)
@@ -11,7 +11,7 @@
  */
 
 /*
- * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008
  *
  * 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
 #include <linux/rcupdate.h>
 #include <linux/list.h>
 
+#include "netlabel_addrlist.h"
+
 /* Domain hash table size */
 /* XXX - currently this number is an uneducated guess */
 #define NETLBL_DOMHSH_BITSIZE       7
 
-/* Domain mapping definition struct */
+/* Domain mapping definition structures */
+#define netlbl_domhsh_addr4_entry(iter) \
+       container_of(iter, struct netlbl_domaddr4_map, list)
+struct netlbl_domaddr4_map {
+       u32 type;
+       union {
+               struct cipso_v4_doi *cipsov4;
+       } type_def;
+
+       struct netlbl_af4list list;
+};
+#define netlbl_domhsh_addr6_entry(iter) \
+       container_of(iter, struct netlbl_domaddr6_map, list)
+struct netlbl_domaddr6_map {
+       u32 type;
+
+       /* NOTE: no 'type_def' union needed at present since we don't currently
+        *       support any IPv6 labeling protocols */
+
+       struct netlbl_af6list list;
+};
+struct netlbl_domaddr_map {
+       struct list_head list4;
+       struct list_head list6;
+};
 struct netlbl_dom_map {
        char *domain;
        u32 type;
        union {
                struct cipso_v4_doi *cipsov4;
+               struct netlbl_domaddr_map *addrsel;
        } type_def;
 
        u32 valid;
@@ -61,12 +88,21 @@ int netlbl_domhsh_add(struct netlbl_dom_map *entry,
                      struct netlbl_audit *audit_info);
 int netlbl_domhsh_add_default(struct netlbl_dom_map *entry,
                              struct netlbl_audit *audit_info);
+int netlbl_domhsh_remove_entry(struct netlbl_dom_map *entry,
+                              struct netlbl_audit *audit_info);
 int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info);
 int netlbl_domhsh_remove_default(struct netlbl_audit *audit_info);
 struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain);
+struct netlbl_domaddr4_map *netlbl_domhsh_getentry_af4(const char *domain,
+                                                      __be32 addr);
 int netlbl_domhsh_walk(u32 *skip_bkt,
                     u32 *skip_chain,
                     int (*callback) (struct netlbl_dom_map *entry, void *arg),
                     void *cb_arg);
 
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+struct netlbl_domaddr6_map *netlbl_domhsh_getentry_af6(const char *domain,
+                                                 const struct in6_addr *addr);
+#endif /* IPv6 */
+
 #endif
index 39793a1a93aaba375a6bf7382081c245b197e38b..b32eceb3ab0d526ad0c021e4e1feeaebdf3293e6 100644 (file)
@@ -10,7 +10,7 @@
  */
 
 /*
- * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008
  *
  * 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
@@ -82,7 +82,7 @@ int netlbl_cfg_unlbl_add_map(const char *domain,
 
        entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
        if (entry == NULL)
-               goto cfg_unlbl_add_map_failure;
+               return -ENOMEM;
        if (domain != NULL) {
                entry->domain = kstrdup(domain, GFP_ATOMIC);
                if (entry->domain == NULL)
@@ -103,49 +103,6 @@ cfg_unlbl_add_map_failure:
        return ret_val;
 }
 
-/**
- * netlbl_cfg_cipsov4_add - Add a new CIPSOv4 DOI definition
- * @doi_def: the DOI definition
- * @audit_info: NetLabel audit information
- *
- * Description:
- * Add a new CIPSOv4 DOI definition to the NetLabel subsystem.  Returns zero on
- * success, negative values on failure.
- *
- */
-int netlbl_cfg_cipsov4_add(struct cipso_v4_doi *doi_def,
-                          struct netlbl_audit *audit_info)
-{
-       int ret_val;
-       const char *type_str;
-       struct audit_buffer *audit_buf;
-
-       ret_val = cipso_v4_doi_add(doi_def);
-
-       audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_ADD,
-                                             audit_info);
-       if (audit_buf != NULL) {
-               switch (doi_def->type) {
-               case CIPSO_V4_MAP_STD:
-                       type_str = "std";
-                       break;
-               case CIPSO_V4_MAP_PASS:
-                       type_str = "pass";
-                       break;
-               default:
-                       type_str = "(unknown)";
-               }
-               audit_log_format(audit_buf,
-                                " cipso_doi=%u cipso_type=%s res=%u",
-                                doi_def->doi,
-                                type_str,
-                                ret_val == 0 ? 1 : 0);
-               audit_log_end(audit_buf);
-       }
-
-       return ret_val;
-}
-
 /**
  * netlbl_cfg_cipsov4_add_map - Add a new CIPSOv4 DOI definition and mapping
  * @doi_def: the DOI definition
@@ -164,58 +121,71 @@ int netlbl_cfg_cipsov4_add_map(struct cipso_v4_doi *doi_def,
                               struct netlbl_audit *audit_info)
 {
        int ret_val = -ENOMEM;
+       u32 doi;
+       u32 doi_type;
        struct netlbl_dom_map *entry;
+       const char *type_str;
+       struct audit_buffer *audit_buf;
+
+       doi = doi_def->doi;
+       doi_type = doi_def->type;
 
        entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
        if (entry == NULL)
-               goto cfg_cipsov4_add_map_failure;
+               return -ENOMEM;
        if (domain != NULL) {
                entry->domain = kstrdup(domain, GFP_ATOMIC);
                if (entry->domain == NULL)
                        goto cfg_cipsov4_add_map_failure;
        }
-       entry->type = NETLBL_NLTYPE_CIPSOV4;
-       entry->type_def.cipsov4 = doi_def;
-
-       /* Grab a RCU read lock here so nothing happens to the doi_def variable
-        * between adding it to the CIPSOv4 protocol engine and adding a
-        * domain mapping for it. */
 
-       rcu_read_lock();
-       ret_val = netlbl_cfg_cipsov4_add(doi_def, audit_info);
+       ret_val = cipso_v4_doi_add(doi_def);
        if (ret_val != 0)
-               goto cfg_cipsov4_add_map_failure_unlock;
+               goto cfg_cipsov4_add_map_failure_remove_doi;
+       entry->type = NETLBL_NLTYPE_CIPSOV4;
+       entry->type_def.cipsov4 = cipso_v4_doi_getdef(doi);
+       if (entry->type_def.cipsov4 == NULL) {
+               ret_val = -ENOENT;
+               goto cfg_cipsov4_add_map_failure_remove_doi;
+       }
        ret_val = netlbl_domhsh_add(entry, audit_info);
        if (ret_val != 0)
-               goto cfg_cipsov4_add_map_failure_remove_doi;
-       rcu_read_unlock();
+               goto cfg_cipsov4_add_map_failure_release_doi;
 
-       return 0;
+cfg_cipsov4_add_map_return:
+       audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_ADD,
+                                             audit_info);
+       if (audit_buf != NULL) {
+               switch (doi_type) {
+               case CIPSO_V4_MAP_TRANS:
+                       type_str = "trans";
+                       break;
+               case CIPSO_V4_MAP_PASS:
+                       type_str = "pass";
+                       break;
+               case CIPSO_V4_MAP_LOCAL:
+                       type_str = "local";
+                       break;
+               default:
+                       type_str = "(unknown)";
+               }
+               audit_log_format(audit_buf,
+                                " cipso_doi=%u cipso_type=%s res=%u",
+                                doi, type_str, ret_val == 0 ? 1 : 0);
+               audit_log_end(audit_buf);
+       }
 
+       return ret_val;
+
+cfg_cipsov4_add_map_failure_release_doi:
+       cipso_v4_doi_putdef(doi_def);
 cfg_cipsov4_add_map_failure_remove_doi:
-       cipso_v4_doi_remove(doi_def->doi, audit_info, netlbl_cipsov4_doi_free);
-cfg_cipsov4_add_map_failure_unlock:
-       rcu_read_unlock();
+       cipso_v4_doi_remove(doi, audit_info);
 cfg_cipsov4_add_map_failure:
        if (entry != NULL)
                kfree(entry->domain);
        kfree(entry);
-       return ret_val;
-}
-
-/**
- * netlbl_cfg_cipsov4_del - Removean existing CIPSOv4 DOI definition
- * @doi: the CIPSO DOI value
- * @audit_info: NetLabel audit information
- *
- * Description:
- * Removes an existing CIPSOv4 DOI definition from the NetLabel subsystem.
- * Returns zero on success, negative values on failure.
- *
- */
-int netlbl_cfg_cipsov4_del(u32 doi, struct netlbl_audit *audit_info)
-{
-       return cipso_v4_doi_remove(doi, audit_info, netlbl_cipsov4_doi_free);
+       goto cfg_cipsov4_add_map_return;
 }
 
 /*
@@ -452,7 +422,9 @@ int netlbl_enabled(void)
  * Attach the correct label to the given socket using the security attributes
  * specified in @secattr.  This function requires exclusive access to @sk,
  * which means it either needs to be in the process of being created or locked.
- * Returns zero on success, negative values on failure.
+ * Returns zero on success, -EDESTADDRREQ if the domain is configured to use
+ * network address selectors (can't blindly label the socket), and negative
+ * values on all other failures.
  *
  */
 int netlbl_sock_setattr(struct sock *sk,
@@ -466,6 +438,9 @@ int netlbl_sock_setattr(struct sock *sk,
        if (dom_entry == NULL)
                goto socket_setattr_return;
        switch (dom_entry->type) {
+       case NETLBL_NLTYPE_ADDRSELECT:
+               ret_val = -EDESTADDRREQ;
+               break;
        case NETLBL_NLTYPE_CIPSOV4:
                ret_val = cipso_v4_sock_setattr(sk,
                                                dom_entry->type_def.cipsov4,
@@ -483,6 +458,20 @@ socket_setattr_return:
        return ret_val;
 }
 
+/**
+ * netlbl_sock_delattr - Delete all the NetLabel labels on a socket
+ * @sk: the socket
+ *
+ * Description:
+ * Remove all the NetLabel labeling from @sk.  The caller is responsible for
+ * ensuring that @sk is locked.
+ *
+ */
+void netlbl_sock_delattr(struct sock *sk)
+{
+       cipso_v4_sock_delattr(sk);
+}
+
 /**
  * netlbl_sock_getattr - Determine the security attributes of a sock
  * @sk: the sock
@@ -500,6 +489,128 @@ int netlbl_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr)
        return cipso_v4_sock_getattr(sk, secattr);
 }
 
+/**
+ * netlbl_conn_setattr - Label a connected socket using the correct protocol
+ * @sk: the socket to label
+ * @addr: the destination address
+ * @secattr: the security attributes
+ *
+ * Description:
+ * Attach the correct label to the given connected socket using the security
+ * attributes specified in @secattr.  The caller is responsible for ensuring
+ * that @sk is locked.  Returns zero on success, negative values on failure.
+ *
+ */
+int netlbl_conn_setattr(struct sock *sk,
+                       struct sockaddr *addr,
+                       const struct netlbl_lsm_secattr *secattr)
+{
+       int ret_val;
+       struct sockaddr_in *addr4;
+       struct netlbl_domaddr4_map *af4_entry;
+
+       rcu_read_lock();
+       switch (addr->sa_family) {
+       case AF_INET:
+               addr4 = (struct sockaddr_in *)addr;
+               af4_entry = netlbl_domhsh_getentry_af4(secattr->domain,
+                                                      addr4->sin_addr.s_addr);
+               if (af4_entry == NULL) {
+                       ret_val = -ENOENT;
+                       goto conn_setattr_return;
+               }
+               switch (af4_entry->type) {
+               case NETLBL_NLTYPE_CIPSOV4:
+                       ret_val = cipso_v4_sock_setattr(sk,
+                                                  af4_entry->type_def.cipsov4,
+                                                  secattr);
+                       break;
+               case NETLBL_NLTYPE_UNLABELED:
+                       /* just delete the protocols we support for right now
+                        * but we could remove other protocols if needed */
+                       cipso_v4_sock_delattr(sk);
+                       ret_val = 0;
+                       break;
+               default:
+                       ret_val = -ENOENT;
+               }
+               break;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       case AF_INET6:
+               /* since we don't support any IPv6 labeling protocols right
+                * now we can optimize everything away until we do */
+               ret_val = 0;
+               break;
+#endif /* IPv6 */
+       default:
+               ret_val = 0;
+       }
+
+conn_setattr_return:
+       rcu_read_unlock();
+       return ret_val;
+}
+
+/**
+ * netlbl_skbuff_setattr - Label a packet using the correct protocol
+ * @skb: the packet
+ * @family: protocol family
+ * @secattr: the security attributes
+ *
+ * Description:
+ * Attach the correct label to the given packet using the security attributes
+ * specified in @secattr.  Returns zero on success, negative values on failure.
+ *
+ */
+int netlbl_skbuff_setattr(struct sk_buff *skb,
+                         u16 family,
+                         const struct netlbl_lsm_secattr *secattr)
+{
+       int ret_val;
+       struct iphdr *hdr4;
+       struct netlbl_domaddr4_map *af4_entry;
+
+       rcu_read_lock();
+       switch (family) {
+       case AF_INET:
+               hdr4 = ip_hdr(skb);
+               af4_entry = netlbl_domhsh_getentry_af4(secattr->domain,
+                                                      hdr4->daddr);
+               if (af4_entry == NULL) {
+                       ret_val = -ENOENT;
+                       goto skbuff_setattr_return;
+               }
+               switch (af4_entry->type) {
+               case NETLBL_NLTYPE_CIPSOV4:
+                       ret_val = cipso_v4_skbuff_setattr(skb,
+                                                  af4_entry->type_def.cipsov4,
+                                                  secattr);
+                       break;
+               case NETLBL_NLTYPE_UNLABELED:
+                       /* just delete the protocols we support for right now
+                        * but we could remove other protocols if needed */
+                       ret_val = cipso_v4_skbuff_delattr(skb);
+                       break;
+               default:
+                       ret_val = -ENOENT;
+               }
+               break;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       case AF_INET6:
+               /* since we don't support any IPv6 labeling protocols right
+                * now we can optimize everything away until we do */
+               ret_val = 0;
+               break;
+#endif /* IPv6 */
+       default:
+               ret_val = 0;
+       }
+
+skbuff_setattr_return:
+       rcu_read_unlock();
+       return ret_val;
+}
+
 /**
  * netlbl_skbuff_getattr - Determine the security attributes of a packet
  * @skb: the packet
@@ -528,6 +639,7 @@ int netlbl_skbuff_getattr(const struct sk_buff *skb,
  * netlbl_skbuff_err - Handle a LSM error on a sk_buff
  * @skb: the packet
  * @error: the error code
+ * @gateway: true if host is acting as a gateway, false otherwise
  *
  * Description:
  * Deal with a LSM problem when handling the packet in @skb, typically this is
@@ -535,10 +647,10 @@ int netlbl_skbuff_getattr(const struct sk_buff *skb,
  * according to the packet's labeling protocol.
  *
  */
-void netlbl_skbuff_err(struct sk_buff *skb, int error)
+void netlbl_skbuff_err(struct sk_buff *skb, int error, int gateway)
 {
        if (CIPSO_V4_OPTEXIST(skb))
-               cipso_v4_error(skb, error, 0);
+               cipso_v4_error(skb, error, gateway);
 }
 
 /**
index 44be5d5261f4670005f44276f5fb5a257fe97538..ee769ecaa13cf149f137a8a88b3606673b325cee 100644 (file)
@@ -10,7 +10,7 @@
  */
 
 /*
- * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008
  *
  * 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
 #include <linux/socket.h>
 #include <linux/string.h>
 #include <linux/skbuff.h>
+#include <linux/in.h>
+#include <linux/in6.h>
 #include <net/sock.h>
 #include <net/netlink.h>
 #include <net/genetlink.h>
+#include <net/ip.h>
+#include <net/ipv6.h>
 #include <net/netlabel.h>
 #include <net/cipso_ipv4.h>
 #include <asm/atomic.h>
@@ -71,85 +75,336 @@ static const struct nla_policy netlbl_mgmt_genl_policy[NLBL_MGMT_A_MAX + 1] = {
 };
 
 /*
- * NetLabel Command Handlers
+ * Helper Functions
  */
 
 /**
  * netlbl_mgmt_add - Handle an ADD message
- * @skb: the NETLINK buffer
  * @info: the Generic NETLINK info block
+ * @audit_info: NetLabel audit information
  *
  * Description:
- * Process a user generated ADD message and add the domains from the message
- * to the hash table.  See netlabel.h for a description of the message format.
- * Returns zero on success, negative values on failure.
+ * Helper function for the ADD and ADDDEF messages to add the domain mappings
+ * from the message to the hash table.  See netlabel.h for a description of the
+ * message format.  Returns zero on success, negative values on failure.
  *
  */
-static int netlbl_mgmt_add(struct sk_buff *skb, struct genl_info *info)
+static int netlbl_mgmt_add_common(struct genl_info *info,
+                                 struct netlbl_audit *audit_info)
 {
        int ret_val = -EINVAL;
        struct netlbl_dom_map *entry = NULL;
-       size_t tmp_size;
+       struct netlbl_domaddr_map *addrmap = NULL;
+       struct cipso_v4_doi *cipsov4 = NULL;
        u32 tmp_val;
-       struct netlbl_audit audit_info;
-
-       if (!info->attrs[NLBL_MGMT_A_DOMAIN] ||
-           !info->attrs[NLBL_MGMT_A_PROTOCOL])
-               goto add_failure;
-
-       netlbl_netlink_auditinfo(skb, &audit_info);
 
        entry = kzalloc(sizeof(*entry), GFP_KERNEL);
        if (entry == NULL) {
                ret_val = -ENOMEM;
                goto add_failure;
        }
-       tmp_size = nla_len(info->attrs[NLBL_MGMT_A_DOMAIN]);
-       entry->domain = kmalloc(tmp_size, GFP_KERNEL);
-       if (entry->domain == NULL) {
-               ret_val = -ENOMEM;
-               goto add_failure;
-       }
        entry->type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]);
-       nla_strlcpy(entry->domain, info->attrs[NLBL_MGMT_A_DOMAIN], tmp_size);
+       if (info->attrs[NLBL_MGMT_A_DOMAIN]) {
+               size_t tmp_size = nla_len(info->attrs[NLBL_MGMT_A_DOMAIN]);
+               entry->domain = kmalloc(tmp_size, GFP_KERNEL);
+               if (entry->domain == NULL) {
+                       ret_val = -ENOMEM;
+                       goto add_failure;
+               }
+               nla_strlcpy(entry->domain,
+                           info->attrs[NLBL_MGMT_A_DOMAIN], tmp_size);
+       }
+
+       /* NOTE: internally we allow/use a entry->type value of
+        *       NETLBL_NLTYPE_ADDRSELECT but we don't currently allow users
+        *       to pass that as a protocol value because we need to know the
+        *       "real" protocol */
 
        switch (entry->type) {
        case NETLBL_NLTYPE_UNLABELED:
-               ret_val = netlbl_domhsh_add(entry, &audit_info);
                break;
        case NETLBL_NLTYPE_CIPSOV4:
                if (!info->attrs[NLBL_MGMT_A_CV4DOI])
                        goto add_failure;
 
                tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CV4DOI]);
-               /* We should be holding a rcu_read_lock() here while we hold
-                * the result but since the entry will always be deleted when
-                * the CIPSO DOI is deleted we aren't going to keep the
-                * lock. */
-               rcu_read_lock();
-               entry->type_def.cipsov4 = cipso_v4_doi_getdef(tmp_val);
-               if (entry->type_def.cipsov4 == NULL) {
-                       rcu_read_unlock();
+               cipsov4 = cipso_v4_doi_getdef(tmp_val);
+               if (cipsov4 == NULL)
                        goto add_failure;
-               }
-               ret_val = netlbl_domhsh_add(entry, &audit_info);
-               rcu_read_unlock();
+               entry->type_def.cipsov4 = cipsov4;
                break;
        default:
                goto add_failure;
        }
+
+       if (info->attrs[NLBL_MGMT_A_IPV4ADDR]) {
+               struct in_addr *addr;
+               struct in_addr *mask;
+               struct netlbl_domaddr4_map *map;
+
+               addrmap = kzalloc(sizeof(*addrmap), GFP_KERNEL);
+               if (addrmap == NULL) {
+                       ret_val = -ENOMEM;
+                       goto add_failure;
+               }
+               INIT_LIST_HEAD(&addrmap->list4);
+               INIT_LIST_HEAD(&addrmap->list6);
+
+               if (nla_len(info->attrs[NLBL_MGMT_A_IPV4ADDR]) !=
+                   sizeof(struct in_addr)) {
+                       ret_val = -EINVAL;
+                       goto add_failure;
+               }
+               if (nla_len(info->attrs[NLBL_MGMT_A_IPV4MASK]) !=
+                   sizeof(struct in_addr)) {
+                       ret_val = -EINVAL;
+                       goto add_failure;
+               }
+               addr = nla_data(info->attrs[NLBL_MGMT_A_IPV4ADDR]);
+               mask = nla_data(info->attrs[NLBL_MGMT_A_IPV4MASK]);
+
+               map = kzalloc(sizeof(*map), GFP_KERNEL);
+               if (map == NULL) {
+                       ret_val = -ENOMEM;
+                       goto add_failure;
+               }
+               map->list.addr = addr->s_addr & mask->s_addr;
+               map->list.mask = mask->s_addr;
+               map->list.valid = 1;
+               map->type = entry->type;
+               if (cipsov4)
+                       map->type_def.cipsov4 = cipsov4;
+
+               ret_val = netlbl_af4list_add(&map->list, &addrmap->list4);
+               if (ret_val != 0) {
+                       kfree(map);
+                       goto add_failure;
+               }
+
+               entry->type = NETLBL_NLTYPE_ADDRSELECT;
+               entry->type_def.addrsel = addrmap;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       } else if (info->attrs[NLBL_MGMT_A_IPV6ADDR]) {
+               struct in6_addr *addr;
+               struct in6_addr *mask;
+               struct netlbl_domaddr6_map *map;
+
+               addrmap = kzalloc(sizeof(*addrmap), GFP_KERNEL);
+               if (addrmap == NULL) {
+                       ret_val = -ENOMEM;
+                       goto add_failure;
+               }
+               INIT_LIST_HEAD(&addrmap->list4);
+               INIT_LIST_HEAD(&addrmap->list6);
+
+               if (nla_len(info->attrs[NLBL_MGMT_A_IPV6ADDR]) !=
+                   sizeof(struct in6_addr)) {
+                       ret_val = -EINVAL;
+                       goto add_failure;
+               }
+               if (nla_len(info->attrs[NLBL_MGMT_A_IPV6MASK]) !=
+                   sizeof(struct in6_addr)) {
+                       ret_val = -EINVAL;
+                       goto add_failure;
+               }
+               addr = nla_data(info->attrs[NLBL_MGMT_A_IPV6ADDR]);
+               mask = nla_data(info->attrs[NLBL_MGMT_A_IPV6MASK]);
+
+               map = kzalloc(sizeof(*map), GFP_KERNEL);
+               if (map == NULL) {
+                       ret_val = -ENOMEM;
+                       goto add_failure;
+               }
+               ipv6_addr_copy(&map->list.addr, addr);
+               map->list.addr.s6_addr32[0] &= mask->s6_addr32[0];
+               map->list.addr.s6_addr32[1] &= mask->s6_addr32[1];
+               map->list.addr.s6_addr32[2] &= mask->s6_addr32[2];
+               map->list.addr.s6_addr32[3] &= mask->s6_addr32[3];
+               ipv6_addr_copy(&map->list.mask, mask);
+               map->list.valid = 1;
+               map->type = entry->type;
+
+               ret_val = netlbl_af6list_add(&map->list, &addrmap->list6);
+               if (ret_val != 0) {
+                       kfree(map);
+                       goto add_failure;
+               }
+
+               entry->type = NETLBL_NLTYPE_ADDRSELECT;
+               entry->type_def.addrsel = addrmap;
+#endif /* IPv6 */
+       }
+
+       ret_val = netlbl_domhsh_add(entry, audit_info);
        if (ret_val != 0)
                goto add_failure;
 
        return 0;
 
 add_failure:
+       if (cipsov4)
+               cipso_v4_doi_putdef(cipsov4);
        if (entry)
                kfree(entry->domain);
+       kfree(addrmap);
        kfree(entry);
        return ret_val;
 }
 
+/**
+ * netlbl_mgmt_listentry - List a NetLabel/LSM domain map entry
+ * @skb: the NETLINK buffer
+ * @entry: the map entry
+ *
+ * Description:
+ * This function is a helper function used by the LISTALL and LISTDEF command
+ * handlers.  The caller is responsibile for ensuring that the RCU read lock
+ * is held.  Returns zero on success, negative values on failure.
+ *
+ */
+static int netlbl_mgmt_listentry(struct sk_buff *skb,
+                                struct netlbl_dom_map *entry)
+{
+       int ret_val;
+       struct nlattr *nla_a;
+       struct nlattr *nla_b;
+       struct netlbl_af4list *iter4;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       struct netlbl_af6list *iter6;
+#endif
+
+       if (entry->domain != NULL) {
+               ret_val = nla_put_string(skb,
+                                        NLBL_MGMT_A_DOMAIN, entry->domain);
+               if (ret_val != 0)
+                       return ret_val;
+       }
+
+       switch (entry->type) {
+       case NETLBL_NLTYPE_ADDRSELECT:
+               nla_a = nla_nest_start(skb, NLBL_MGMT_A_SELECTORLIST);
+               if (nla_a == NULL)
+                       return -ENOMEM;
+
+               netlbl_af4list_foreach_rcu(iter4,
+                                          &entry->type_def.addrsel->list4) {
+                       struct netlbl_domaddr4_map *map4;
+                       struct in_addr addr_struct;
+
+                       nla_b = nla_nest_start(skb, NLBL_MGMT_A_ADDRSELECTOR);
+                       if (nla_b == NULL)
+                               return -ENOMEM;
+
+                       addr_struct.s_addr = iter4->addr;
+                       ret_val = nla_put(skb, NLBL_MGMT_A_IPV4ADDR,
+                                         sizeof(struct in_addr),
+                                         &addr_struct);
+                       if (ret_val != 0)
+                               return ret_val;
+                       addr_struct.s_addr = iter4->mask;
+                       ret_val = nla_put(skb, NLBL_MGMT_A_IPV4MASK,
+                                         sizeof(struct in_addr),
+                                         &addr_struct);
+                       if (ret_val != 0)
+                               return ret_val;
+                       map4 = netlbl_domhsh_addr4_entry(iter4);
+                       ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
+                                             map4->type);
+                       if (ret_val != 0)
+                               return ret_val;
+                       switch (map4->type) {
+                       case NETLBL_NLTYPE_CIPSOV4:
+                               ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI,
+                                                 map4->type_def.cipsov4->doi);
+                               if (ret_val != 0)
+                                       return ret_val;
+                               break;
+                       }
+
+                       nla_nest_end(skb, nla_b);
+               }
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+               netlbl_af6list_foreach_rcu(iter6,
+                                          &entry->type_def.addrsel->list6) {
+                       struct netlbl_domaddr6_map *map6;
+
+                       nla_b = nla_nest_start(skb, NLBL_MGMT_A_ADDRSELECTOR);
+                       if (nla_b == NULL)
+                               return -ENOMEM;
+
+                       ret_val = nla_put(skb, NLBL_MGMT_A_IPV6ADDR,
+                                         sizeof(struct in6_addr),
+                                         &iter6->addr);
+                       if (ret_val != 0)
+                               return ret_val;
+                       ret_val = nla_put(skb, NLBL_MGMT_A_IPV6MASK,
+                                         sizeof(struct in6_addr),
+                                         &iter6->mask);
+                       if (ret_val != 0)
+                               return ret_val;
+                       map6 = netlbl_domhsh_addr6_entry(iter6);
+                       ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
+                                             map6->type);
+                       if (ret_val != 0)
+                               return ret_val;
+
+                       nla_nest_end(skb, nla_b);
+               }
+#endif /* IPv6 */
+
+               nla_nest_end(skb, nla_a);
+               break;
+       case NETLBL_NLTYPE_UNLABELED:
+               ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, entry->type);
+               break;
+       case NETLBL_NLTYPE_CIPSOV4:
+               ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, entry->type);
+               if (ret_val != 0)
+                       return ret_val;
+               ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI,
+                                     entry->type_def.cipsov4->doi);
+               break;
+       }
+
+       return ret_val;
+}
+
+/*
+ * NetLabel Command Handlers
+ */
+
+/**
+ * netlbl_mgmt_add - Handle an ADD message
+ * @skb: the NETLINK buffer
+ * @info: the Generic NETLINK info block
+ *
+ * Description:
+ * Process a user generated ADD message and add the domains from the message
+ * to the hash table.  See netlabel.h for a description of the message format.
+ * Returns zero on success, negative values on failure.
+ *
+ */
+static int netlbl_mgmt_add(struct sk_buff *skb, struct genl_info *info)
+{
+       struct netlbl_audit audit_info;
+
+       if ((!info->attrs[NLBL_MGMT_A_DOMAIN]) ||
+           (!info->attrs[NLBL_MGMT_A_PROTOCOL]) ||
+           (info->attrs[NLBL_MGMT_A_IPV4ADDR] &&
+            info->attrs[NLBL_MGMT_A_IPV6ADDR]) ||
+           (info->attrs[NLBL_MGMT_A_IPV4MASK] &&
+            info->attrs[NLBL_MGMT_A_IPV6MASK]) ||
+           ((info->attrs[NLBL_MGMT_A_IPV4ADDR] != NULL) ^
+            (info->attrs[NLBL_MGMT_A_IPV4MASK] != NULL)) ||
+           ((info->attrs[NLBL_MGMT_A_IPV6ADDR] != NULL) ^
+            (info->attrs[NLBL_MGMT_A_IPV6MASK] != NULL)))
+               return -EINVAL;
+
+       netlbl_netlink_auditinfo(skb, &audit_info);
+
+       return netlbl_mgmt_add_common(info, &audit_info);
+}
+
 /**
  * netlbl_mgmt_remove - Handle a REMOVE message
  * @skb: the NETLINK buffer
@@ -198,23 +453,9 @@ static int netlbl_mgmt_listall_cb(struct netlbl_dom_map *entry, void *arg)
        if (data == NULL)
                goto listall_cb_failure;
 
-       ret_val = nla_put_string(cb_arg->skb,
-                                NLBL_MGMT_A_DOMAIN,
-                                entry->domain);
+       ret_val = netlbl_mgmt_listentry(cb_arg->skb, entry);
        if (ret_val != 0)
                goto listall_cb_failure;
-       ret_val = nla_put_u32(cb_arg->skb, NLBL_MGMT_A_PROTOCOL, entry->type);
-       if (ret_val != 0)
-               goto listall_cb_failure;
-       switch (entry->type) {
-       case NETLBL_NLTYPE_CIPSOV4:
-               ret_val = nla_put_u32(cb_arg->skb,
-                                     NLBL_MGMT_A_CV4DOI,
-                                     entry->type_def.cipsov4->doi);
-               if (ret_val != 0)
-                       goto listall_cb_failure;
-               break;
-       }
 
        cb_arg->seq++;
        return genlmsg_end(cb_arg->skb, data);
@@ -268,56 +509,22 @@ static int netlbl_mgmt_listall(struct sk_buff *skb,
  */
 static int netlbl_mgmt_adddef(struct sk_buff *skb, struct genl_info *info)
 {
-       int ret_val = -EINVAL;
-       struct netlbl_dom_map *entry = NULL;
-       u32 tmp_val;
        struct netlbl_audit audit_info;
 
-       if (!info->attrs[NLBL_MGMT_A_PROTOCOL])
-               goto adddef_failure;
+       if ((!info->attrs[NLBL_MGMT_A_PROTOCOL]) ||
+           (info->attrs[NLBL_MGMT_A_IPV4ADDR] &&
+            info->attrs[NLBL_MGMT_A_IPV6ADDR]) ||
+           (info->attrs[NLBL_MGMT_A_IPV4MASK] &&
+            info->attrs[NLBL_MGMT_A_IPV6MASK]) ||
+           ((info->attrs[NLBL_MGMT_A_IPV4ADDR] != NULL) ^
+            (info->attrs[NLBL_MGMT_A_IPV4MASK] != NULL)) ||
+           ((info->attrs[NLBL_MGMT_A_IPV6ADDR] != NULL) ^
+            (info->attrs[NLBL_MGMT_A_IPV6MASK] != NULL)))
+               return -EINVAL;
 
        netlbl_netlink_auditinfo(skb, &audit_info);
 
-       entry = kzalloc(sizeof(*entry), GFP_KERNEL);
-       if (entry == NULL) {
-               ret_val = -ENOMEM;
-               goto adddef_failure;
-       }
-       entry->type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]);
-
-       switch (entry->type) {
-       case NETLBL_NLTYPE_UNLABELED:
-               ret_val = netlbl_domhsh_add_default(entry, &audit_info);
-               break;
-       case NETLBL_NLTYPE_CIPSOV4:
-               if (!info->attrs[NLBL_MGMT_A_CV4DOI])
-                       goto adddef_failure;
-
-               tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CV4DOI]);
-               /* We should be holding a rcu_read_lock() here while we hold
-                * the result but since the entry will always be deleted when
-                * the CIPSO DOI is deleted we aren't going to keep the
-                * lock. */
-               rcu_read_lock();
-               entry->type_def.cipsov4 = cipso_v4_doi_getdef(tmp_val);
-               if (entry->type_def.cipsov4 == NULL) {
-                       rcu_read_unlock();
-                       goto adddef_failure;
-               }
-               ret_val = netlbl_domhsh_add_default(entry, &audit_info);
-               rcu_read_unlock();
-               break;
-       default:
-               goto adddef_failure;
-       }
-       if (ret_val != 0)
-               goto adddef_failure;
-
-       return 0;
-
-adddef_failure:
-       kfree(entry);
-       return ret_val;
+       return netlbl_mgmt_add_common(info, &audit_info);
 }
 
 /**
@@ -371,19 +578,10 @@ static int netlbl_mgmt_listdef(struct sk_buff *skb, struct genl_info *info)
                ret_val = -ENOENT;
                goto listdef_failure_lock;
        }
-       ret_val = nla_put_u32(ans_skb, NLBL_MGMT_A_PROTOCOL, entry->type);
-       if (ret_val != 0)
-               goto listdef_failure_lock;
-       switch (entry->type) {
-       case NETLBL_NLTYPE_CIPSOV4:
-               ret_val = nla_put_u32(ans_skb,
-                                     NLBL_MGMT_A_CV4DOI,
-                                     entry->type_def.cipsov4->doi);
-               if (ret_val != 0)
-                       goto listdef_failure_lock;
-               break;
-       }
+       ret_val = netlbl_mgmt_listentry(ans_skb, entry);
        rcu_read_unlock();
+       if (ret_val != 0)
+               goto listdef_failure;
 
        genlmsg_end(ans_skb, data);
        return genlmsg_reply(ans_skb, info);
index a43bff169d6b5f793b0550b6b4fa65b5a53b37c5..05d96431f81984061b575fd6adbad5c5de2ced19 100644 (file)
  *     NLBL_MGMT_A_DOMAIN
  *     NLBL_MGMT_A_PROTOCOL
  *
+ *   If IPv4 is specified the following attributes are required:
+ *
+ *     NLBL_MGMT_A_IPV4ADDR
+ *     NLBL_MGMT_A_IPV4MASK
+ *
+ *   If IPv6 is specified the following attributes are required:
+ *
+ *     NLBL_MGMT_A_IPV6ADDR
+ *     NLBL_MGMT_A_IPV6MASK
+ *
  *   If using NETLBL_NLTYPE_CIPSOV4 the following attributes are required:
  *
  *     NLBL_MGMT_A_CV4DOI
  *   Required attributes:
  *
  *     NLBL_MGMT_A_DOMAIN
+ *
+ *   If the IP address selectors are not used the following attribute is
+ *   required:
+ *
  *     NLBL_MGMT_A_PROTOCOL
  *
- *   If using NETLBL_NLTYPE_CIPSOV4 the following attributes are required:
+ *   If the IP address selectors are used then the following attritbute is
+ *   required:
+ *
+ *     NLBL_MGMT_A_SELECTORLIST
+ *
+ *   If the mapping is using the NETLBL_NLTYPE_CIPSOV4 type then the following
+ *   attributes are required:
  *
  *     NLBL_MGMT_A_CV4DOI
  *
- *   If using NETLBL_NLTYPE_UNLABELED no other attributes are required.
+ *   If the mapping is using the NETLBL_NLTYPE_UNLABELED type no other
+ *   attributes are required.
  *
  * o ADDDEF:
  *   Sent by an application to set the default domain mapping for the NetLabel
  *   application there is no payload.  On success the kernel should send a
  *   response using the following format.
  *
- *   Required attributes:
+ *   If the IP address selectors are not used the following attribute is
+ *   required:
  *
  *     NLBL_MGMT_A_PROTOCOL
  *
- *   If using NETLBL_NLTYPE_CIPSOV4 the following attributes are required:
+ *   If the IP address selectors are used then the following attritbute is
+ *   required:
+ *
+ *     NLBL_MGMT_A_SELECTORLIST
+ *
+ *   If the mapping is using the NETLBL_NLTYPE_CIPSOV4 type then the following
+ *   attributes are required:
  *
  *     NLBL_MGMT_A_CV4DOI
  *
- *   If using NETLBL_NLTYPE_UNLABELED no other attributes are required.
+ *   If the mapping is using the NETLBL_NLTYPE_UNLABELED type no other
+ *   attributes are required.
  *
  * o PROTOCOLS:
  *   Sent by an application to request a list of configured NetLabel protocols
@@ -162,6 +191,26 @@ enum {
        NLBL_MGMT_A_CV4DOI,
        /* (NLA_U32)
         * the CIPSOv4 DOI value */
+       NLBL_MGMT_A_IPV6ADDR,
+       /* (NLA_BINARY, struct in6_addr)
+        * an IPv6 address */
+       NLBL_MGMT_A_IPV6MASK,
+       /* (NLA_BINARY, struct in6_addr)
+        * an IPv6 address mask */
+       NLBL_MGMT_A_IPV4ADDR,
+       /* (NLA_BINARY, struct in_addr)
+        * an IPv4 address */
+       NLBL_MGMT_A_IPV4MASK,
+       /* (NLA_BINARY, struct in_addr)
+        * and IPv4 address mask */
+       NLBL_MGMT_A_ADDRSELECTOR,
+       /* (NLA_NESTED)
+        * an IP address selector, must contain an address, mask, and protocol
+        * attribute plus any protocol specific attributes */
+       NLBL_MGMT_A_SELECTORLIST,
+       /* (NLA_NESTED)
+        * the selector list, there must be at least one
+        * NLBL_MGMT_A_ADDRSELECTOR attribute */
        __NLBL_MGMT_A_MAX,
 };
 #define NLBL_MGMT_A_MAX (__NLBL_MGMT_A_MAX - 1)
index 921c118ead891991f0337d4bb29689adabe586c6..e8a5c32b0f106042c82790c2e1c924837bfe0b64 100644 (file)
@@ -10,7 +10,7 @@
  */
 
 /*
- * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 - 2007
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 - 2008
  *
  * 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
@@ -54,6 +54,7 @@
 #include <asm/atomic.h>
 
 #include "netlabel_user.h"
+#include "netlabel_addrlist.h"
 #include "netlabel_domainhash.h"
 #include "netlabel_unlabeled.h"
 #include "netlabel_mgmt.h"
@@ -76,22 +77,20 @@ struct netlbl_unlhsh_tbl {
        struct list_head *tbl;
        u32 size;
 };
+#define netlbl_unlhsh_addr4_entry(iter) \
+       container_of(iter, struct netlbl_unlhsh_addr4, list)
 struct netlbl_unlhsh_addr4 {
-       __be32 addr;
-       __be32 mask;
        u32 secid;
 
-       u32 valid;
-       struct list_head list;
+       struct netlbl_af4list list;
        struct rcu_head rcu;
 };
+#define netlbl_unlhsh_addr6_entry(iter) \
+       container_of(iter, struct netlbl_unlhsh_addr6, list)
 struct netlbl_unlhsh_addr6 {
-       struct in6_addr addr;
-       struct in6_addr mask;
        u32 secid;
 
-       u32 valid;
-       struct list_head list;
+       struct netlbl_af6list list;
        struct rcu_head rcu;
 };
 struct netlbl_unlhsh_iface {
@@ -146,76 +145,6 @@ static const struct nla_policy netlbl_unlabel_genl_policy[NLBL_UNLABEL_A_MAX + 1
        [NLBL_UNLABEL_A_SECCTX] = { .type = NLA_BINARY }
 };
 
-/*
- * Audit Helper Functions
- */
-
-/**
- * netlbl_unlabel_audit_addr4 - Audit an IPv4 address
- * @audit_buf: audit buffer
- * @dev: network interface
- * @addr: IP address
- * @mask: IP address mask
- *
- * Description:
- * Write the IPv4 address and address mask, if necessary, to @audit_buf.
- *
- */
-static void netlbl_unlabel_audit_addr4(struct audit_buffer *audit_buf,
-                                    const char *dev,
-                                    __be32 addr, __be32 mask)
-{
-       u32 mask_val = ntohl(mask);
-
-       if (dev != NULL)
-               audit_log_format(audit_buf, " netif=%s", dev);
-       audit_log_format(audit_buf, " src=" NIPQUAD_FMT, NIPQUAD(addr));
-       if (mask_val != 0xffffffff) {
-               u32 mask_len = 0;
-               while (mask_val > 0) {
-                       mask_val <<= 1;
-                       mask_len++;
-               }
-               audit_log_format(audit_buf, " src_prefixlen=%d", mask_len);
-       }
-}
-
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-/**
- * netlbl_unlabel_audit_addr6 - Audit an IPv6 address
- * @audit_buf: audit buffer
- * @dev: network interface
- * @addr: IP address
- * @mask: IP address mask
- *
- * Description:
- * Write the IPv6 address and address mask, if necessary, to @audit_buf.
- *
- */
-static void netlbl_unlabel_audit_addr6(struct audit_buffer *audit_buf,
-                                    const char *dev,
-                                    const struct in6_addr *addr,
-                                    const struct in6_addr *mask)
-{
-       if (dev != NULL)
-               audit_log_format(audit_buf, " netif=%s", dev);
-       audit_log_format(audit_buf, " src=" NIP6_FMT, NIP6(*addr));
-       if (ntohl(mask->s6_addr32[3]) != 0xffffffff) {
-               u32 mask_len = 0;
-               u32 mask_val;
-               int iter = -1;
-               while (ntohl(mask->s6_addr32[++iter]) == 0xffffffff)
-                       mask_len += 32;
-               mask_val = ntohl(mask->s6_addr32[iter]);
-               while (mask_val > 0) {
-                       mask_val <<= 1;
-                       mask_len++;
-               }
-               audit_log_format(audit_buf, " src_prefixlen=%d", mask_len);
-       }
-}
-#endif /* IPv6 */
-
 /*
  * Unlabeled Connection Hash Table Functions
  */
@@ -274,26 +203,28 @@ static void netlbl_unlhsh_free_addr6(struct rcu_head *entry)
 static void netlbl_unlhsh_free_iface(struct rcu_head *entry)
 {
        struct netlbl_unlhsh_iface *iface;
-       struct netlbl_unlhsh_addr4 *iter4;
-       struct netlbl_unlhsh_addr4 *tmp4;
-       struct netlbl_unlhsh_addr6 *iter6;
-       struct netlbl_unlhsh_addr6 *tmp6;
+       struct netlbl_af4list *iter4;
+       struct netlbl_af4list *tmp4;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       struct netlbl_af6list *iter6;
+       struct netlbl_af6list *tmp6;
+#endif /* IPv6 */
 
        iface = container_of(entry, struct netlbl_unlhsh_iface, rcu);
 
        /* no need for locks here since we are the only one with access to this
         * structure */
 
-       list_for_each_entry_safe(iter4, tmp4, &iface->addr4_list, list)
-               if (iter4->valid) {
-                       list_del_rcu(&iter4->list);
-                       kfree(iter4);
-               }
-       list_for_each_entry_safe(iter6, tmp6, &iface->addr6_list, list)
-               if (iter6->valid) {
-                       list_del_rcu(&iter6->list);
-                       kfree(iter6);
-               }
+       netlbl_af4list_foreach_safe(iter4, tmp4, &iface->addr4_list) {
+               netlbl_af4list_remove_entry(iter4);
+               kfree(netlbl_unlhsh_addr4_entry(iter4));
+       }
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       netlbl_af6list_foreach_safe(iter6, tmp6, &iface->addr6_list) {
+               netlbl_af6list_remove_entry(iter6);
+               kfree(netlbl_unlhsh_addr6_entry(iter6));
+       }
+#endif /* IPv6 */
        kfree(iface);
 }
 
@@ -315,59 +246,6 @@ static u32 netlbl_unlhsh_hash(int ifindex)
        return ifindex & (rcu_dereference(netlbl_unlhsh)->size - 1);
 }
 
-/**
- * netlbl_unlhsh_search_addr4 - Search for a matching IPv4 address entry
- * @addr: IPv4 address
- * @iface: the network interface entry
- *
- * Description:
- * Searches the IPv4 address list of the network interface specified by @iface.
- * If a matching address entry is found it is returned, otherwise NULL is
- * returned.  The caller is responsible for calling the rcu_read_[un]lock()
- * functions.
- *
- */
-static struct netlbl_unlhsh_addr4 *netlbl_unlhsh_search_addr4(
-                                      __be32 addr,
-                                      const struct netlbl_unlhsh_iface *iface)
-{
-       struct netlbl_unlhsh_addr4 *iter;
-
-       list_for_each_entry_rcu(iter, &iface->addr4_list, list)
-               if (iter->valid && (addr & iter->mask) == iter->addr)
-                       return iter;
-
-       return NULL;
-}
-
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-/**
- * netlbl_unlhsh_search_addr6 - Search for a matching IPv6 address entry
- * @addr: IPv6 address
- * @iface: the network interface entry
- *
- * Description:
- * Searches the IPv6 address list of the network interface specified by @iface.
- * If a matching address entry is found it is returned, otherwise NULL is
- * returned.  The caller is responsible for calling the rcu_read_[un]lock()
- * functions.
- *
- */
-static struct netlbl_unlhsh_addr6 *netlbl_unlhsh_search_addr6(
-                                      const struct in6_addr *addr,
-                                      const struct netlbl_unlhsh_iface *iface)
-{
-       struct netlbl_unlhsh_addr6 *iter;
-
-       list_for_each_entry_rcu(iter, &iface->addr6_list, list)
-               if (iter->valid &&
-                   ipv6_masked_addr_cmp(&iter->addr, &iter->mask, addr) == 0)
-               return iter;
-
-       return NULL;
-}
-#endif /* IPv6 */
-
 /**
  * netlbl_unlhsh_search_iface - Search for a matching interface entry
  * @ifindex: the network interface
@@ -381,12 +259,12 @@ static struct netlbl_unlhsh_addr6 *netlbl_unlhsh_search_addr6(
 static struct netlbl_unlhsh_iface *netlbl_unlhsh_search_iface(int ifindex)
 {
        u32 bkt;
+       struct list_head *bkt_list;
        struct netlbl_unlhsh_iface *iter;
 
        bkt = netlbl_unlhsh_hash(ifindex);
-       list_for_each_entry_rcu(iter,
-                               &rcu_dereference(netlbl_unlhsh)->tbl[bkt],
-                               list)
+       bkt_list = &rcu_dereference(netlbl_unlhsh)->tbl[bkt];
+       list_for_each_entry_rcu(iter, bkt_list, list)
                if (iter->valid && iter->ifindex == ifindex)
                        return iter;
 
@@ -439,43 +317,26 @@ static int netlbl_unlhsh_add_addr4(struct netlbl_unlhsh_iface *iface,
                                   const struct in_addr *mask,
                                   u32 secid)
 {
+       int ret_val;
        struct netlbl_unlhsh_addr4 *entry;
-       struct netlbl_unlhsh_addr4 *iter;
 
        entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
        if (entry == NULL)
                return -ENOMEM;
 
-       entry->addr = addr->s_addr & mask->s_addr;
-       entry->mask = mask->s_addr;
-       entry->secid = secid;
-       entry->valid = 1;
+       entry->list.addr = addr->s_addr & mask->s_addr;
+       entry->list.mask = mask->s_addr;
+       entry->list.valid = 1;
        INIT_RCU_HEAD(&entry->rcu);
+       entry->secid = secid;
 
        spin_lock(&netlbl_unlhsh_lock);
-       iter = netlbl_unlhsh_search_addr4(entry->addr, iface);
-       if (iter != NULL &&
-           iter->addr == addr->s_addr && iter->mask == mask->s_addr) {
-               spin_unlock(&netlbl_unlhsh_lock);
-               kfree(entry);
-               return -EEXIST;
-       }
-       /* in order to speed up address searches through the list (the common
-        * case) we need to keep the list in order based on the size of the
-        * address mask such that the entry with the widest mask (smallest
-        * numerical value) appears first in the list */
-       list_for_each_entry_rcu(iter, &iface->addr4_list, list)
-               if (iter->valid &&
-                   ntohl(entry->mask) > ntohl(iter->mask)) {
-                       __list_add_rcu(&entry->list,
-                                      iter->list.prev,
-                                      &iter->list);
-                       spin_unlock(&netlbl_unlhsh_lock);
-                       return 0;
-               }
-       list_add_tail_rcu(&entry->list, &iface->addr4_list);
+       ret_val = netlbl_af4list_add(&entry->list, &iface->addr4_list);
        spin_unlock(&netlbl_unlhsh_lock);
-       return 0;
+
+       if (ret_val != 0)
+               kfree(entry);
+       return ret_val;
 }
 
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
@@ -498,47 +359,29 @@ static int netlbl_unlhsh_add_addr6(struct netlbl_unlhsh_iface *iface,
                                   const struct in6_addr *mask,
                                   u32 secid)
 {
+       int ret_val;
        struct netlbl_unlhsh_addr6 *entry;
-       struct netlbl_unlhsh_addr6 *iter;
 
        entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
        if (entry == NULL)
                return -ENOMEM;
 
-       ipv6_addr_copy(&entry->addr, addr);
-       entry->addr.s6_addr32[0] &= mask->s6_addr32[0];
-       entry->addr.s6_addr32[1] &= mask->s6_addr32[1];
-       entry->addr.s6_addr32[2] &= mask->s6_addr32[2];
-       entry->addr.s6_addr32[3] &= mask->s6_addr32[3];
-       ipv6_addr_copy(&entry->mask, mask);
-       entry->secid = secid;
-       entry->valid = 1;
+       ipv6_addr_copy(&entry->list.addr, addr);
+       entry->list.addr.s6_addr32[0] &= mask->s6_addr32[0];
+       entry->list.addr.s6_addr32[1] &= mask->s6_addr32[1];
+       entry->list.addr.s6_addr32[2] &= mask->s6_addr32[2];
+       entry->list.addr.s6_addr32[3] &= mask->s6_addr32[3];
+       ipv6_addr_copy(&entry->list.mask, mask);
+       entry->list.valid = 1;
        INIT_RCU_HEAD(&entry->rcu);
+       entry->secid = secid;
 
        spin_lock(&netlbl_unlhsh_lock);
-       iter = netlbl_unlhsh_search_addr6(&entry->addr, iface);
-       if (iter != NULL &&
-           (ipv6_addr_equal(&iter->addr, addr) &&
-            ipv6_addr_equal(&iter->mask, mask))) {
-               spin_unlock(&netlbl_unlhsh_lock);
-               kfree(entry);
-               return -EEXIST;
-       }
-       /* in order to speed up address searches through the list (the common
-        * case) we need to keep the list in order based on the size of the
-        * address mask such that the entry with the widest mask (smallest
-        * numerical value) appears first in the list */
-       list_for_each_entry_rcu(iter, &iface->addr6_list, list)
-               if (iter->valid &&
-                   ipv6_addr_cmp(&entry->mask, &iter->mask) > 0) {
-                       __list_add_rcu(&entry->list,
-                                      iter->list.prev,
-                                      &iter->list);
-                       spin_unlock(&netlbl_unlhsh_lock);
-                       return 0;
-               }
-       list_add_tail_rcu(&entry->list, &iface->addr6_list);
+       ret_val = netlbl_af6list_add(&entry->list, &iface->addr6_list);
        spin_unlock(&netlbl_unlhsh_lock);
+
+       if (ret_val != 0)
+               kfree(entry);
        return 0;
 }
 #endif /* IPv6 */
@@ -658,10 +501,10 @@ static int netlbl_unlhsh_add(struct net *net,
                mask4 = (struct in_addr *)mask;
                ret_val = netlbl_unlhsh_add_addr4(iface, addr4, mask4, secid);
                if (audit_buf != NULL)
-                       netlbl_unlabel_audit_addr4(audit_buf,
-                                                  dev_name,
-                                                  addr4->s_addr,
-                                                  mask4->s_addr);
+                       netlbl_af4list_audit_addr(audit_buf, 1,
+                                                 dev_name,
+                                                 addr4->s_addr,
+                                                 mask4->s_addr);
                break;
        }
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
@@ -672,9 +515,9 @@ static int netlbl_unlhsh_add(struct net *net,
                mask6 = (struct in6_addr *)mask;
                ret_val = netlbl_unlhsh_add_addr6(iface, addr6, mask6, secid);
                if (audit_buf != NULL)
-                       netlbl_unlabel_audit_addr6(audit_buf,
-                                                  dev_name,
-                                                  addr6, mask6);
+                       netlbl_af6list_audit_addr(audit_buf, 1,
+                                                 dev_name,
+                                                 addr6, mask6);
                break;
        }
 #endif /* IPv6 */
@@ -719,35 +562,34 @@ static int netlbl_unlhsh_remove_addr4(struct net *net,
                                      const struct in_addr *mask,
                                      struct netlbl_audit *audit_info)
 {
-       int ret_val = -ENOENT;
+       int ret_val = 0;
+       struct netlbl_af4list *list_entry;
        struct netlbl_unlhsh_addr4 *entry;
-       struct audit_buffer *audit_buf = NULL;
+       struct audit_buffer *audit_buf;
        struct net_device *dev;
-       char *secctx = NULL;
+       char *secctx;
        u32 secctx_len;
 
        spin_lock(&netlbl_unlhsh_lock);
-       entry = netlbl_unlhsh_search_addr4(addr->s_addr, iface);
-       if (entry != NULL &&
-           entry->addr == addr->s_addr && entry->mask == mask->s_addr) {
-               entry->valid = 0;
-               list_del_rcu(&entry->list);
-               ret_val = 0;
-       }
+       list_entry = netlbl_af4list_remove(addr->s_addr, mask->s_addr,
+                                          &iface->addr4_list);
        spin_unlock(&netlbl_unlhsh_lock);
+       if (list_entry == NULL)
+               ret_val = -ENOENT;
+       entry = netlbl_unlhsh_addr4_entry(list_entry);
 
        audit_buf = netlbl_audit_start_common(AUDIT_MAC_UNLBL_STCDEL,
                                              audit_info);
        if (audit_buf != NULL) {
                dev = dev_get_by_index(net, iface->ifindex);
-               netlbl_unlabel_audit_addr4(audit_buf,
-                                          (dev != NULL ? dev->name : NULL),
-                                          entry->addr, entry->mask);
+               netlbl_af4list_audit_addr(audit_buf, 1,
+                                         (dev != NULL ? dev->name : NULL),
+                                         addr->s_addr, mask->s_addr);
                if (dev != NULL)
                        dev_put(dev);
-               if (security_secid_to_secctx(entry->secid,
-                                            &secctx,
-                                            &secctx_len) == 0) {
+               if (entry && security_secid_to_secctx(entry->secid,
+                                                     &secctx,
+                                                     &secctx_len) == 0) {
                        audit_log_format(audit_buf, " sec_obj=%s", secctx);
                        security_release_secctx(secctx, secctx_len);
                }
@@ -781,36 +623,33 @@ static int netlbl_unlhsh_remove_addr6(struct net *net,
                                      const struct in6_addr *mask,
                                      struct netlbl_audit *audit_info)
 {
-       int ret_val = -ENOENT;
+       int ret_val = 0;
+       struct netlbl_af6list *list_entry;
        struct netlbl_unlhsh_addr6 *entry;
-       struct audit_buffer *audit_buf = NULL;
+       struct audit_buffer *audit_buf;
        struct net_device *dev;
-       char *secctx = NULL;
+       char *secctx;
        u32 secctx_len;
 
        spin_lock(&netlbl_unlhsh_lock);
-       entry = netlbl_unlhsh_search_addr6(addr, iface);
-       if (entry != NULL &&
-           (ipv6_addr_equal(&entry->addr, addr) &&
-            ipv6_addr_equal(&entry->mask, mask))) {
-               entry->valid = 0;
-               list_del_rcu(&entry->list);
-               ret_val = 0;
-       }
+       list_entry = netlbl_af6list_remove(addr, mask, &iface->addr6_list);
        spin_unlock(&netlbl_unlhsh_lock);
+       if (list_entry == NULL)
+               ret_val = -ENOENT;
+       entry = netlbl_unlhsh_addr6_entry(list_entry);
 
        audit_buf = netlbl_audit_start_common(AUDIT_MAC_UNLBL_STCDEL,
                                              audit_info);
        if (audit_buf != NULL) {
                dev = dev_get_by_index(net, iface->ifindex);
-               netlbl_unlabel_audit_addr6(audit_buf,
-                                          (dev != NULL ? dev->name : NULL),
-                                          addr, mask);
+               netlbl_af6list_audit_addr(audit_buf, 1,
+                                         (dev != NULL ? dev->name : NULL),
+                                         addr, mask);
                if (dev != NULL)
                        dev_put(dev);
-               if (security_secid_to_secctx(entry->secid,
-                                            &secctx,
-                                            &secctx_len) == 0) {
+               if (entry && security_secid_to_secctx(entry->secid,
+                                                     &secctx,
+                                                     &secctx_len) == 0) {
                        audit_log_format(audit_buf, " sec_obj=%s", secctx);
                        security_release_secctx(secctx, secctx_len);
                }
@@ -836,16 +675,18 @@ static int netlbl_unlhsh_remove_addr6(struct net *net,
  */
 static void netlbl_unlhsh_condremove_iface(struct netlbl_unlhsh_iface *iface)
 {
-       struct netlbl_unlhsh_addr4 *iter4;
-       struct netlbl_unlhsh_addr6 *iter6;
+       struct netlbl_af4list *iter4;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       struct netlbl_af6list *iter6;
+#endif /* IPv6 */
 
        spin_lock(&netlbl_unlhsh_lock);
-       list_for_each_entry_rcu(iter4, &iface->addr4_list, list)
-               if (iter4->valid)
-                       goto unlhsh_condremove_failure;
-       list_for_each_entry_rcu(iter6, &iface->addr6_list, list)
-               if (iter6->valid)
-                       goto unlhsh_condremove_failure;
+       netlbl_af4list_foreach_rcu(iter4, &iface->addr4_list)
+               goto unlhsh_condremove_failure;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       netlbl_af6list_foreach_rcu(iter6, &iface->addr6_list)
+               goto unlhsh_condremove_failure;
+#endif /* IPv6 */
        iface->valid = 0;
        if (iface->ifindex > 0)
                list_del_rcu(&iface->list);
@@ -1349,7 +1190,7 @@ static int netlbl_unlabel_staticlist_gen(u32 cmd,
        if (addr4) {
                struct in_addr addr_struct;
 
-               addr_struct.s_addr = addr4->addr;
+               addr_struct.s_addr = addr4->list.addr;
                ret_val = nla_put(cb_arg->skb,
                                  NLBL_UNLABEL_A_IPV4ADDR,
                                  sizeof(struct in_addr),
@@ -1357,7 +1198,7 @@ static int netlbl_unlabel_staticlist_gen(u32 cmd,
                if (ret_val != 0)
                        goto list_cb_failure;
 
-               addr_struct.s_addr = addr4->mask;
+               addr_struct.s_addr = addr4->list.mask;
                ret_val = nla_put(cb_arg->skb,
                                  NLBL_UNLABEL_A_IPV4MASK,
                                  sizeof(struct in_addr),
@@ -1370,14 +1211,14 @@ static int netlbl_unlabel_staticlist_gen(u32 cmd,
                ret_val = nla_put(cb_arg->skb,
                                  NLBL_UNLABEL_A_IPV6ADDR,
                                  sizeof(struct in6_addr),
-                                 &addr6->addr);
+                                 &addr6->list.addr);
                if (ret_val != 0)
                        goto list_cb_failure;
 
                ret_val = nla_put(cb_arg->skb,
                                  NLBL_UNLABEL_A_IPV6MASK,
                                  sizeof(struct in6_addr),
-                                 &addr6->mask);
+                                 &addr6->list.mask);
                if (ret_val != 0)
                        goto list_cb_failure;
 
@@ -1425,8 +1266,11 @@ static int netlbl_unlabel_staticlist(struct sk_buff *skb,
        u32 iter_bkt;
        u32 iter_chain = 0, iter_addr4 = 0, iter_addr6 = 0;
        struct netlbl_unlhsh_iface *iface;
-       struct netlbl_unlhsh_addr4 *addr4;
-       struct netlbl_unlhsh_addr6 *addr6;
+       struct list_head *iter_list;
+       struct netlbl_af4list *addr4;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       struct netlbl_af6list *addr6;
+#endif
 
        cb_arg.nl_cb = cb;
        cb_arg.skb = skb;
@@ -1436,44 +1280,43 @@ static int netlbl_unlabel_staticlist(struct sk_buff *skb,
        for (iter_bkt = skip_bkt;
             iter_bkt < rcu_dereference(netlbl_unlhsh)->size;
             iter_bkt++, iter_chain = 0, iter_addr4 = 0, iter_addr6 = 0) {
-               list_for_each_entry_rcu(iface,
-                               &rcu_dereference(netlbl_unlhsh)->tbl[iter_bkt],
-                               list) {
+               iter_list = &rcu_dereference(netlbl_unlhsh)->tbl[iter_bkt];
+               list_for_each_entry_rcu(iface, iter_list, list) {
                        if (!iface->valid ||
                            iter_chain++ < skip_chain)
                                continue;
-                       list_for_each_entry_rcu(addr4,
-                                               &iface->addr4_list,
-                                               list) {
-                               if (!addr4->valid || iter_addr4++ < skip_addr4)
+                       netlbl_af4list_foreach_rcu(addr4,
+                                                  &iface->addr4_list) {
+                               if (iter_addr4++ < skip_addr4)
                                        continue;
                                if (netlbl_unlabel_staticlist_gen(
-                                                    NLBL_UNLABEL_C_STATICLIST,
-                                                    iface,
-                                                    addr4,
-                                                    NULL,
-                                                    &cb_arg) < 0) {
+                                             NLBL_UNLABEL_C_STATICLIST,
+                                             iface,
+                                             netlbl_unlhsh_addr4_entry(addr4),
+                                             NULL,
+                                             &cb_arg) < 0) {
                                        iter_addr4--;
                                        iter_chain--;
                                        goto unlabel_staticlist_return;
                                }
                        }
-                       list_for_each_entry_rcu(addr6,
-                                               &iface->addr6_list,
-                                               list) {
-                               if (!addr6->valid || iter_addr6++ < skip_addr6)
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+                       netlbl_af6list_foreach_rcu(addr6,
+                                                  &iface->addr6_list) {
+                               if (iter_addr6++ < skip_addr6)
                                        continue;
                                if (netlbl_unlabel_staticlist_gen(
-                                                    NLBL_UNLABEL_C_STATICLIST,
-                                                    iface,
-                                                    NULL,
-                                                    addr6,
-                                                    &cb_arg) < 0) {
+                                             NLBL_UNLABEL_C_STATICLIST,
+                                             iface,
+                                             NULL,
+                                             netlbl_unlhsh_addr6_entry(addr6),
+                                             &cb_arg) < 0) {
                                        iter_addr6--;
                                        iter_chain--;
                                        goto unlabel_staticlist_return;
                                }
                        }
+#endif /* IPv6 */
                }
        }
 
@@ -1504,9 +1347,12 @@ static int netlbl_unlabel_staticlistdef(struct sk_buff *skb,
        struct netlbl_unlhsh_iface *iface;
        u32 skip_addr4 = cb->args[0];
        u32 skip_addr6 = cb->args[1];
-       u32 iter_addr4 = 0, iter_addr6 = 0;
-       struct netlbl_unlhsh_addr4 *addr4;
-       struct netlbl_unlhsh_addr6 *addr6;
+       u32 iter_addr4 = 0;
+       struct netlbl_af4list *addr4;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       u32 iter_addr6 = 0;
+       struct netlbl_af6list *addr6;
+#endif
 
        cb_arg.nl_cb = cb;
        cb_arg.skb = skb;
@@ -1517,30 +1363,32 @@ static int netlbl_unlabel_staticlistdef(struct sk_buff *skb,
        if (iface == NULL || !iface->valid)
                goto unlabel_staticlistdef_return;
 
-       list_for_each_entry_rcu(addr4, &iface->addr4_list, list) {
-               if (!addr4->valid || iter_addr4++ < skip_addr4)
+       netlbl_af4list_foreach_rcu(addr4, &iface->addr4_list) {
+               if (iter_addr4++ < skip_addr4)
                        continue;
                if (netlbl_unlabel_staticlist_gen(NLBL_UNLABEL_C_STATICLISTDEF,
-                                          iface,
-                                          addr4,
-                                          NULL,
-                                          &cb_arg) < 0) {
+                                             iface,
+                                             netlbl_unlhsh_addr4_entry(addr4),
+                                             NULL,
+                                             &cb_arg) < 0) {
                        iter_addr4--;
                        goto unlabel_staticlistdef_return;
                }
        }
-       list_for_each_entry_rcu(addr6, &iface->addr6_list, list) {
-               if (!addr6->valid || iter_addr6++ < skip_addr6)
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       netlbl_af6list_foreach_rcu(addr6, &iface->addr6_list) {
+               if (iter_addr6++ < skip_addr6)
                        continue;
                if (netlbl_unlabel_staticlist_gen(NLBL_UNLABEL_C_STATICLISTDEF,
-                                          iface,
-                                          NULL,
-                                          addr6,
-                                          &cb_arg) < 0) {
+                                             iface,
+                                             NULL,
+                                             netlbl_unlhsh_addr6_entry(addr6),
+                                             &cb_arg) < 0) {
                        iter_addr6--;
                        goto unlabel_staticlistdef_return;
                }
        }
+#endif /* IPv6 */
 
 unlabel_staticlistdef_return:
        rcu_read_unlock();
@@ -1718,25 +1566,27 @@ int netlbl_unlabel_getattr(const struct sk_buff *skb,
        switch (family) {
        case PF_INET: {
                struct iphdr *hdr4;
-               struct netlbl_unlhsh_addr4 *addr4;
+               struct netlbl_af4list *addr4;
 
                hdr4 = ip_hdr(skb);
-               addr4 = netlbl_unlhsh_search_addr4(hdr4->saddr, iface);
+               addr4 = netlbl_af4list_search(hdr4->saddr,
+                                             &iface->addr4_list);
                if (addr4 == NULL)
                        goto unlabel_getattr_nolabel;
-               secattr->attr.secid = addr4->secid;
+               secattr->attr.secid = netlbl_unlhsh_addr4_entry(addr4)->secid;
                break;
        }
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
        case PF_INET6: {
                struct ipv6hdr *hdr6;
-               struct netlbl_unlhsh_addr6 *addr6;
+               struct netlbl_af6list *addr6;
 
                hdr6 = ipv6_hdr(skb);
-               addr6 = netlbl_unlhsh_search_addr6(&hdr6->saddr, iface);
+               addr6 = netlbl_af6list_search(&hdr6->saddr,
+                                             &iface->addr6_list);
                if (addr6 == NULL)
                        goto unlabel_getattr_nolabel;
-               secattr->attr.secid = addr6->secid;
+               secattr->attr.secid = netlbl_unlhsh_addr6_entry(addr6)->secid;
                break;
        }
 #endif /* IPv6 */
index 4c9890ec252875500c6c35d388fdd44af9545f34..473f94e56eade0f26195a6afadc90559a11cef2c 100644 (file)
@@ -629,6 +629,59 @@ static int do_i2c_entry(const char *filename, struct i2c_device_id *id,
        return 1;
 }
 
+static const struct dmifield {
+       const char *prefix;
+       int field;
+} dmi_fields[] = {
+       { "bvn", DMI_BIOS_VENDOR },
+       { "bvr", DMI_BIOS_VERSION },
+       { "bd",  DMI_BIOS_DATE },
+       { "svn", DMI_SYS_VENDOR },
+       { "pn",  DMI_PRODUCT_NAME },
+       { "pvr", DMI_PRODUCT_VERSION },
+       { "rvn", DMI_BOARD_VENDOR },
+       { "rn",  DMI_BOARD_NAME },
+       { "rvr", DMI_BOARD_VERSION },
+       { "cvn", DMI_CHASSIS_VENDOR },
+       { "ct",  DMI_CHASSIS_TYPE },
+       { "cvr", DMI_CHASSIS_VERSION },
+       { NULL,  DMI_NONE }
+};
+
+static void dmi_ascii_filter(char *d, const char *s)
+{
+       /* Filter out characters we don't want to see in the modalias string */
+       for (; *s; s++)
+               if (*s > ' ' && *s < 127 && *s != ':')
+                       *(d++) = *s;
+
+       *d = 0;
+}
+
+
+static int do_dmi_entry(const char *filename, struct dmi_system_id *id,
+                       char *alias)
+{
+       int i, j;
+
+       sprintf(alias, "dmi*");
+
+       for (i = 0; i < ARRAY_SIZE(dmi_fields); i++) {
+               for (j = 0; j < 4; j++) {
+                       if (id->matches[j].slot &&
+                           id->matches[j].slot == dmi_fields[i].field) {
+                               sprintf(alias + strlen(alias), ":%s*",
+                                       dmi_fields[i].prefix);
+                               dmi_ascii_filter(alias + strlen(alias),
+                                                id->matches[j].substr);
+                               strcat(alias, "*");
+                       }
+               }
+       }
+
+       strcat(alias, ":");
+       return 1;
+}
 /* Ignore any prefix, eg. some architectures prepend _ */
 static inline int sym_is(const char *symbol, const char *name)
 {
@@ -760,6 +813,10 @@ void handle_moddevtable(struct module *mod, struct elf_info *info,
                do_table(symval, sym->st_size,
                         sizeof(struct i2c_device_id), "i2c",
                         do_i2c_entry, mod);
+       else if (sym_is(symname, "__mod_dmi_device_table"))
+               do_table(symval, sym->st_size,
+                        sizeof(struct dmi_system_id), "dmi",
+                        do_dmi_entry, mod);
        free(zeros);
 }
 
index ca4958ebad8d30c7c4f8ce4bdf1b98309fe2e13e..efea5a6054663f2d2aba78930bd3185986e14cdd 100644 (file)
@@ -20,8 +20,7 @@
 #include <linux/init.h>
 #include <linux/namei.h>
 #include <linux/security.h>
-
-#define SECURITYFS_MAGIC       0x73636673
+#include <linux/magic.h>
 
 static struct vfsmount *mount;
 static int mount_count;
index 4a7374c12d9ca5a2b9c76c1101ecb42ee44b48af..88f19536efadd7980c8a13970976d47ee487d0bd 100644 (file)
@@ -291,6 +291,7 @@ static void sk_free_security(struct sock *sk)
        struct sk_security_struct *ssec = sk->sk_security;
 
        sk->sk_security = NULL;
+       selinux_netlbl_sk_security_free(ssec);
        kfree(ssec);
 }
 
@@ -2121,7 +2122,6 @@ static inline void flush_unauthorized_files(struct files_struct *files)
        long j = -1;
        int drop_tty = 0;
 
-       mutex_lock(&tty_mutex);
        tty = get_current_tty();
        if (tty) {
                file_list_lock();
@@ -2139,8 +2139,8 @@ static inline void flush_unauthorized_files(struct files_struct *files)
                        }
                }
                file_list_unlock();
+               tty_kref_put(tty);
        }
-       mutex_unlock(&tty_mutex);
        /* Reset controlling tty. */
        if (drop_tty)
                no_tty();
@@ -3801,6 +3801,7 @@ out:
 
 static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen)
 {
+       struct sock *sk = sock->sk;
        struct inode_security_struct *isec;
        int err;
 
@@ -3814,7 +3815,6 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address,
        isec = SOCK_INODE(sock)->i_security;
        if (isec->sclass == SECCLASS_TCP_SOCKET ||
            isec->sclass == SECCLASS_DCCP_SOCKET) {
-               struct sock *sk = sock->sk;
                struct avc_audit_data ad;
                struct sockaddr_in *addr4 = NULL;
                struct sockaddr_in6 *addr6 = NULL;
@@ -3848,6 +3848,8 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address,
                        goto out;
        }
 
+       err = selinux_netlbl_socket_connect(sk, address);
+
 out:
        return err;
 }
@@ -4077,20 +4079,28 @@ static int selinux_sock_rcv_skb_iptables_compat(struct sock *sk,
 }
 
 static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
-                                      struct avc_audit_data *ad,
-                                      u16 family, char *addrp)
+                                      u16 family)
 {
        int err;
        struct sk_security_struct *sksec = sk->sk_security;
        u32 peer_sid;
        u32 sk_sid = sksec->sid;
+       struct avc_audit_data ad;
+       char *addrp;
+
+       AVC_AUDIT_DATA_INIT(&ad, NET);
+       ad.u.net.netif = skb->iif;
+       ad.u.net.family = family;
+       err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
+       if (err)
+               return err;
 
        if (selinux_compat_net)
-               err = selinux_sock_rcv_skb_iptables_compat(sk, skb, ad,
+               err = selinux_sock_rcv_skb_iptables_compat(sk, skb, &ad,
                                                           family, addrp);
        else
                err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
-                                  PACKET__RECV, ad);
+                                  PACKET__RECV, &ad);
        if (err)
                return err;
 
@@ -4099,12 +4109,14 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
                if (err)
                        return err;
                err = avc_has_perm(sk_sid, peer_sid,
-                                  SECCLASS_PEER, PEER__RECV, ad);
+                                  SECCLASS_PEER, PEER__RECV, &ad);
+               if (err)
+                       selinux_netlbl_err(skb, err, 0);
        } else {
-               err = selinux_netlbl_sock_rcv_skb(sksec, skb, family, ad);
+               err = selinux_netlbl_sock_rcv_skb(sksec, skb, family, &ad);
                if (err)
                        return err;
-               err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, ad);
+               err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, &ad);
        }
 
        return err;
@@ -4118,6 +4130,8 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
        u32 sk_sid = sksec->sid;
        struct avc_audit_data ad;
        char *addrp;
+       u8 secmark_active;
+       u8 peerlbl_active;
 
        if (family != PF_INET && family != PF_INET6)
                return 0;
@@ -4126,6 +4140,18 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
        if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
                family = PF_INET;
 
+       /* If any sort of compatibility mode is enabled then handoff processing
+        * to the selinux_sock_rcv_skb_compat() function to deal with the
+        * special handling.  We do this in an attempt to keep this function
+        * as fast and as clean as possible. */
+       if (selinux_compat_net || !selinux_policycap_netpeer)
+               return selinux_sock_rcv_skb_compat(sk, skb, family);
+
+       secmark_active = selinux_secmark_enabled();
+       peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled();
+       if (!secmark_active && !peerlbl_active)
+               return 0;
+
        AVC_AUDIT_DATA_INIT(&ad, NET);
        ad.u.net.netif = skb->iif;
        ad.u.net.family = family;
@@ -4133,15 +4159,7 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
        if (err)
                return err;
 
-       /* If any sort of compatibility mode is enabled then handoff processing
-        * to the selinux_sock_rcv_skb_compat() function to deal with the
-        * special handling.  We do this in an attempt to keep this function
-        * as fast and as clean as possible. */
-       if (selinux_compat_net || !selinux_policycap_netpeer)
-               return selinux_sock_rcv_skb_compat(sk, skb, &ad,
-                                                  family, addrp);
-
-       if (netlbl_enabled() || selinux_xfrm_enabled()) {
+       if (peerlbl_active) {
                u32 peer_sid;
 
                err = selinux_skb_peerlbl_sid(skb, family, &peer_sid);
@@ -4149,13 +4167,17 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
                        return err;
                err = selinux_inet_sys_rcv_skb(skb->iif, addrp, family,
                                               peer_sid, &ad);
-               if (err)
+               if (err) {
+                       selinux_netlbl_err(skb, err, 0);
                        return err;
+               }
                err = avc_has_perm(sk_sid, peer_sid, SECCLASS_PEER,
                                   PEER__RECV, &ad);
+               if (err)
+                       selinux_netlbl_err(skb, err, 0);
        }
 
-       if (selinux_secmark_enabled()) {
+       if (secmark_active) {
                err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
                                   PACKET__RECV, &ad);
                if (err)
@@ -4214,10 +4236,12 @@ static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *
        u32 peer_secid = SECSID_NULL;
        u16 family;
 
-       if (sock)
+       if (skb && skb->protocol == htons(ETH_P_IP))
+               family = PF_INET;
+       else if (skb && skb->protocol == htons(ETH_P_IPV6))
+               family = PF_INET6;
+       else if (sock)
                family = sock->sk->sk_family;
-       else if (skb && skb->sk)
-               family = skb->sk->sk_family;
        else
                goto out;
 
@@ -4275,8 +4299,6 @@ static void selinux_sock_graft(struct sock *sk, struct socket *parent)
            sk->sk_family == PF_UNIX)
                isec->sid = sksec->sid;
        sksec->sclass = isec->sclass;
-
-       selinux_netlbl_sock_graft(sk, parent);
 }
 
 static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
@@ -4284,10 +4306,15 @@ static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
 {
        struct sk_security_struct *sksec = sk->sk_security;
        int err;
+       u16 family = sk->sk_family;
        u32 newsid;
        u32 peersid;
 
-       err = selinux_skb_peerlbl_sid(skb, sk->sk_family, &peersid);
+       /* handle mapped IPv4 packets arriving via IPv6 sockets */
+       if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
+               family = PF_INET;
+
+       err = selinux_skb_peerlbl_sid(skb, family, &peersid);
        if (err)
                return err;
        if (peersid == SECSID_NULL) {
@@ -4322,12 +4349,18 @@ static void selinux_inet_csk_clone(struct sock *newsk,
        selinux_netlbl_sk_security_reset(newsksec, req->rsk_ops->family);
 }
 
-static void selinux_inet_conn_established(struct sock *sk,
-                               struct sk_buff *skb)
+static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb)
 {
+       u16 family = sk->sk_family;
        struct sk_security_struct *sksec = sk->sk_security;
 
-       selinux_skb_peerlbl_sid(skb, sk->sk_family, &sksec->peer_sid);
+       /* handle mapped IPv4 packets arriving via IPv6 sockets */
+       if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
+               family = PF_INET;
+
+       selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid);
+
+       selinux_netlbl_inet_conn_established(sk, family);
 }
 
 static void selinux_req_classify_flow(const struct request_sock *req,
@@ -4377,39 +4410,54 @@ out:
 static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex,
                                       u16 family)
 {
+       int err;
        char *addrp;
        u32 peer_sid;
        struct avc_audit_data ad;
        u8 secmark_active;
+       u8 netlbl_active;
        u8 peerlbl_active;
 
        if (!selinux_policycap_netpeer)
                return NF_ACCEPT;
 
        secmark_active = selinux_secmark_enabled();
-       peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled();
+       netlbl_active = netlbl_enabled();
+       peerlbl_active = netlbl_active || selinux_xfrm_enabled();
        if (!secmark_active && !peerlbl_active)
                return NF_ACCEPT;
 
+       if (selinux_skb_peerlbl_sid(skb, family, &peer_sid) != 0)
+               return NF_DROP;
+
        AVC_AUDIT_DATA_INIT(&ad, NET);
        ad.u.net.netif = ifindex;
        ad.u.net.family = family;
        if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0)
                return NF_DROP;
 
-       if (selinux_skb_peerlbl_sid(skb, family, &peer_sid) != 0)
-               return NF_DROP;
-
-       if (peerlbl_active)
-               if (selinux_inet_sys_rcv_skb(ifindex, addrp, family,
-                                            peer_sid, &ad) != 0)
+       if (peerlbl_active) {
+               err = selinux_inet_sys_rcv_skb(ifindex, addrp, family,
+                                              peer_sid, &ad);
+               if (err) {
+                       selinux_netlbl_err(skb, err, 1);
                        return NF_DROP;
+               }
+       }
 
        if (secmark_active)
                if (avc_has_perm(peer_sid, skb->secmark,
                                 SECCLASS_PACKET, PACKET__FORWARD_IN, &ad))
                        return NF_DROP;
 
+       if (netlbl_active)
+               /* we do this in the FORWARD path and not the POST_ROUTING
+                * path because we want to make sure we apply the necessary
+                * labeling before IPsec is applied so we can leverage AH
+                * protection */
+               if (selinux_netlbl_skbuff_setsid(skb, family, peer_sid) != 0)
+                       return NF_DROP;
+
        return NF_ACCEPT;
 }
 
@@ -4433,6 +4481,37 @@ static unsigned int selinux_ipv6_forward(unsigned int hooknum,
 }
 #endif /* IPV6 */
 
+static unsigned int selinux_ip_output(struct sk_buff *skb,
+                                     u16 family)
+{
+       u32 sid;
+
+       if (!netlbl_enabled())
+               return NF_ACCEPT;
+
+       /* we do this in the LOCAL_OUT path and not the POST_ROUTING path
+        * because we want to make sure we apply the necessary labeling
+        * before IPsec is applied so we can leverage AH protection */
+       if (skb->sk) {
+               struct sk_security_struct *sksec = skb->sk->sk_security;
+               sid = sksec->sid;
+       } else
+               sid = SECINITSID_KERNEL;
+       if (selinux_netlbl_skbuff_setsid(skb, family, sid) != 0)
+               return NF_DROP;
+
+       return NF_ACCEPT;
+}
+
+static unsigned int selinux_ipv4_output(unsigned int hooknum,
+                                       struct sk_buff *skb,
+                                       const struct net_device *in,
+                                       const struct net_device *out,
+                                       int (*okfn)(struct sk_buff *))
+{
+       return selinux_ip_output(skb, PF_INET);
+}
+
 static int selinux_ip_postroute_iptables_compat(struct sock *sk,
                                                int ifindex,
                                                struct avc_audit_data *ad,
@@ -4500,30 +4579,36 @@ static int selinux_ip_postroute_iptables_compat(struct sock *sk,
 
 static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
                                                int ifindex,
-                                               struct avc_audit_data *ad,
-                                               u16 family,
-                                               char *addrp,
-                                               u8 proto)
+                                               u16 family)
 {
        struct sock *sk = skb->sk;
        struct sk_security_struct *sksec;
+       struct avc_audit_data ad;
+       char *addrp;
+       u8 proto;
 
        if (sk == NULL)
                return NF_ACCEPT;
        sksec = sk->sk_security;
 
+       AVC_AUDIT_DATA_INIT(&ad, NET);
+       ad.u.net.netif = ifindex;
+       ad.u.net.family = family;
+       if (selinux_parse_skb(skb, &ad, &addrp, 0, &proto))
+               return NF_DROP;
+
        if (selinux_compat_net) {
                if (selinux_ip_postroute_iptables_compat(skb->sk, ifindex,
-                                                        ad, family, addrp))
+                                                        &ad, family, addrp))
                        return NF_DROP;
        } else {
                if (avc_has_perm(sksec->sid, skb->secmark,
-                                SECCLASS_PACKET, PACKET__SEND, ad))
+                                SECCLASS_PACKET, PACKET__SEND, &ad))
                        return NF_DROP;
        }
 
        if (selinux_policycap_netpeer)
-               if (selinux_xfrm_postroute_last(sksec->sid, skb, ad, proto))
+               if (selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto))
                        return NF_DROP;
 
        return NF_ACCEPT;
@@ -4537,23 +4622,15 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
        struct sock *sk;
        struct avc_audit_data ad;
        char *addrp;
-       u8 proto;
        u8 secmark_active;
        u8 peerlbl_active;
 
-       AVC_AUDIT_DATA_INIT(&ad, NET);
-       ad.u.net.netif = ifindex;
-       ad.u.net.family = family;
-       if (selinux_parse_skb(skb, &ad, &addrp, 0, &proto))
-               return NF_DROP;
-
        /* If any sort of compatibility mode is enabled then handoff processing
         * to the selinux_ip_postroute_compat() function to deal with the
         * special handling.  We do this in an attempt to keep this function
         * as fast and as clean as possible. */
        if (selinux_compat_net || !selinux_policycap_netpeer)
-               return selinux_ip_postroute_compat(skb, ifindex, &ad,
-                                                  family, addrp, proto);
+               return selinux_ip_postroute_compat(skb, ifindex, family);
 
        /* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec
         * packet transformation so allow the packet to pass without any checks
@@ -4569,21 +4646,45 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
        if (!secmark_active && !peerlbl_active)
                return NF_ACCEPT;
 
-       /* if the packet is locally generated (skb->sk != NULL) then use the
-        * socket's label as the peer label, otherwise the packet is being
-        * forwarded through this system and we need to fetch the peer label
-        * directly from the packet */
+       /* if the packet is being forwarded then get the peer label from the
+        * packet itself; otherwise check to see if it is from a local
+        * application or the kernel, if from an application get the peer label
+        * from the sending socket, otherwise use the kernel's sid */
        sk = skb->sk;
-       if (sk) {
+       if (sk == NULL) {
+               switch (family) {
+               case PF_INET:
+                       if (IPCB(skb)->flags & IPSKB_FORWARDED)
+                               secmark_perm = PACKET__FORWARD_OUT;
+                       else
+                               secmark_perm = PACKET__SEND;
+                       break;
+               case PF_INET6:
+                       if (IP6CB(skb)->flags & IP6SKB_FORWARDED)
+                               secmark_perm = PACKET__FORWARD_OUT;
+                       else
+                               secmark_perm = PACKET__SEND;
+                       break;
+               default:
+                       return NF_DROP;
+               }
+               if (secmark_perm == PACKET__FORWARD_OUT) {
+                       if (selinux_skb_peerlbl_sid(skb, family, &peer_sid))
+                               return NF_DROP;
+               } else
+                       peer_sid = SECINITSID_KERNEL;
+       } else {
                struct sk_security_struct *sksec = sk->sk_security;
                peer_sid = sksec->sid;
                secmark_perm = PACKET__SEND;
-       } else {
-               if (selinux_skb_peerlbl_sid(skb, family, &peer_sid))
-                               return NF_DROP;
-               secmark_perm = PACKET__FORWARD_OUT;
        }
 
+       AVC_AUDIT_DATA_INIT(&ad, NET);
+       ad.u.net.netif = ifindex;
+       ad.u.net.family = family;
+       if (selinux_parse_skb(skb, &ad, &addrp, 0, NULL))
+               return NF_DROP;
+
        if (secmark_active)
                if (avc_has_perm(peer_sid, skb->secmark,
                                 SECCLASS_PACKET, secmark_perm, &ad))
@@ -5657,6 +5758,13 @@ static struct nf_hook_ops selinux_ipv4_ops[] = {
                .pf =           PF_INET,
                .hooknum =      NF_INET_FORWARD,
                .priority =     NF_IP_PRI_SELINUX_FIRST,
+       },
+       {
+               .hook =         selinux_ipv4_output,
+               .owner =        THIS_MODULE,
+               .pf =           PF_INET,
+               .hooknum =      NF_INET_LOCAL_OUT,
+               .priority =     NF_IP_PRI_SELINUX_FIRST,
        }
 };
 
index 487a7d81fe204ae35df5d96d390b46e7652548fc..b913c8d060386728bfe0bc68441a56b4ad3f012f 100644 (file)
@@ -39,6 +39,9 @@
 #ifdef CONFIG_NETLABEL
 void selinux_netlbl_cache_invalidate(void);
 
+void selinux_netlbl_err(struct sk_buff *skb, int error, int gateway);
+
+void selinux_netlbl_sk_security_free(struct sk_security_struct *ssec);
 void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec,
                                      int family);
 
@@ -46,8 +49,11 @@ int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
                                 u16 family,
                                 u32 *type,
                                 u32 *sid);
+int selinux_netlbl_skbuff_setsid(struct sk_buff *skb,
+                                u16 family,
+                                u32 sid);
 
-void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock);
+void selinux_netlbl_inet_conn_established(struct sock *sk, u16 family);
 int selinux_netlbl_socket_post_create(struct socket *sock);
 int selinux_netlbl_inode_permission(struct inode *inode, int mask);
 int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
@@ -57,12 +63,27 @@ int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
 int selinux_netlbl_socket_setsockopt(struct socket *sock,
                                     int level,
                                     int optname);
+int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr);
+
 #else
 static inline void selinux_netlbl_cache_invalidate(void)
 {
        return;
 }
 
+static inline void selinux_netlbl_err(struct sk_buff *skb,
+                                     int error,
+                                     int gateway)
+{
+       return;
+}
+
+static inline void selinux_netlbl_sk_security_free(
+                                              struct sk_security_struct *ssec)
+{
+       return;
+}
+
 static inline void selinux_netlbl_sk_security_reset(
                                               struct sk_security_struct *ssec,
                                               int family)
@@ -79,9 +100,21 @@ static inline int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
        *sid = SECSID_NULL;
        return 0;
 }
+static inline int selinux_netlbl_skbuff_setsid(struct sk_buff *skb,
+                                              u16 family,
+                                              u32 sid)
+{
+       return 0;
+}
 
-static inline void selinux_netlbl_sock_graft(struct sock *sk,
-                                            struct socket *sock)
+static inline int selinux_netlbl_conn_setsid(struct sock *sk,
+                                            struct sockaddr *addr)
+{
+       return 0;
+}
+
+static inline void selinux_netlbl_inet_conn_established(struct sock *sk,
+                                                       u16 family)
 {
        return;
 }
@@ -107,6 +140,11 @@ static inline int selinux_netlbl_socket_setsockopt(struct socket *sock,
 {
        return 0;
 }
+static inline int selinux_netlbl_socket_connect(struct sock *sk,
+                                               struct sockaddr *addr)
+{
+       return 0;
+}
 #endif /* CONFIG_NETLABEL */
 
 #endif
index 91070ab874ce8b1255fadfff9f99aac0ce5bcc60..f8be8d7fa26d7962f020e612254653d849f5b226 100644 (file)
@@ -109,16 +109,19 @@ struct netport_security_struct {
 };
 
 struct sk_security_struct {
-       u32 sid;                        /* SID of this object */
-       u32 peer_sid;                   /* SID of peer */
-       u16 sclass;                     /* sock security class */
 #ifdef CONFIG_NETLABEL
        enum {                          /* NetLabel state */
                NLBL_UNSET = 0,
                NLBL_REQUIRE,
                NLBL_LABELED,
+               NLBL_REQSKB,
+               NLBL_CONNLABELED,
        } nlbl_state;
+       struct netlbl_lsm_secattr *nlbl_secattr; /* NetLabel sec attributes */
 #endif
+       u32 sid;                        /* SID of this object */
+       u32 peer_sid;                   /* SID of peer */
+       u16 sclass;                     /* sock security class */
 };
 
 struct key_security_struct {
index 89b418392f1179ca13e62d66bb779d6a3f04ccfa..f58701a7b728619a5a50e3bc74981baa23ab60cf 100644 (file)
@@ -9,7 +9,7 @@
  */
 
 /*
- * (c) Copyright Hewlett-Packard Development Company, L.P., 2007
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2007, 2008
  *
  * 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
 
 #include <linux/spinlock.h>
 #include <linux/rcupdate.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
 #include <net/sock.h>
 #include <net/netlabel.h>
+#include <net/ip.h>
+#include <net/ipv6.h>
 
 #include "objsec.h"
 #include "security.h"
@@ -63,33 +67,70 @@ static int selinux_netlbl_sidlookup_cached(struct sk_buff *skb,
        return rc;
 }
 
+/**
+ * selinux_netlbl_sock_genattr - Generate the NetLabel socket secattr
+ * @sk: the socket
+ *
+ * Description:
+ * Generate the NetLabel security attributes for a socket, making full use of
+ * the socket's attribute cache.  Returns a pointer to the security attributes
+ * on success, NULL on failure.
+ *
+ */
+static struct netlbl_lsm_secattr *selinux_netlbl_sock_genattr(struct sock *sk)
+{
+       int rc;
+       struct sk_security_struct *sksec = sk->sk_security;
+       struct netlbl_lsm_secattr *secattr;
+
+       if (sksec->nlbl_secattr != NULL)
+               return sksec->nlbl_secattr;
+
+       secattr = netlbl_secattr_alloc(GFP_ATOMIC);
+       if (secattr == NULL)
+               return NULL;
+       rc = security_netlbl_sid_to_secattr(sksec->sid, secattr);
+       if (rc != 0) {
+               netlbl_secattr_free(secattr);
+               return NULL;
+       }
+       sksec->nlbl_secattr = secattr;
+
+       return secattr;
+}
+
 /**
  * selinux_netlbl_sock_setsid - Label a socket using the NetLabel mechanism
  * @sk: the socket to label
- * @sid: the SID to use
  *
  * Description:
- * Attempt to label a socket using the NetLabel mechanism using the given
- * SID.  Returns zero values on success, negative values on failure.
+ * Attempt to label a socket using the NetLabel mechanism.  Returns zero values
+ * on success, negative values on failure.
  *
  */
-static int selinux_netlbl_sock_setsid(struct sock *sk, u32 sid)
+static int selinux_netlbl_sock_setsid(struct sock *sk)
 {
        int rc;
        struct sk_security_struct *sksec = sk->sk_security;
-       struct netlbl_lsm_secattr secattr;
+       struct netlbl_lsm_secattr *secattr;
 
-       netlbl_secattr_init(&secattr);
+       if (sksec->nlbl_state != NLBL_REQUIRE)
+               return 0;
 
-       rc = security_netlbl_sid_to_secattr(sid, &secattr);
-       if (rc != 0)
-               goto sock_setsid_return;
-       rc = netlbl_sock_setattr(sk, &secattr);
-       if (rc == 0)
+       secattr = selinux_netlbl_sock_genattr(sk);
+       if (secattr == NULL)
+               return -ENOMEM;
+       rc = netlbl_sock_setattr(sk, secattr);
+       switch (rc) {
+       case 0:
                sksec->nlbl_state = NLBL_LABELED;
+               break;
+       case -EDESTADDRREQ:
+               sksec->nlbl_state = NLBL_REQSKB;
+               rc = 0;
+               break;
+       }
 
-sock_setsid_return:
-       netlbl_secattr_destroy(&secattr);
        return rc;
 }
 
@@ -105,6 +146,38 @@ void selinux_netlbl_cache_invalidate(void)
        netlbl_cache_invalidate();
 }
 
+/**
+ * selinux_netlbl_err - Handle a NetLabel packet error
+ * @skb: the packet
+ * @error: the error code
+ * @gateway: true if host is acting as a gateway, false otherwise
+ *
+ * Description:
+ * When a packet is dropped due to a call to avc_has_perm() pass the error
+ * code to the NetLabel subsystem so any protocol specific processing can be
+ * done.  This is safe to call even if you are unsure if NetLabel labeling is
+ * present on the packet, NetLabel is smart enough to only act when it should.
+ *
+ */
+void selinux_netlbl_err(struct sk_buff *skb, int error, int gateway)
+{
+       netlbl_skbuff_err(skb, error, gateway);
+}
+
+/**
+ * selinux_netlbl_sk_security_free - Free the NetLabel fields
+ * @sssec: the sk_security_struct
+ *
+ * Description:
+ * Free all of the memory in the NetLabel fields of a sk_security_struct.
+ *
+ */
+void selinux_netlbl_sk_security_free(struct sk_security_struct *ssec)
+{
+       if (ssec->nlbl_secattr != NULL)
+               netlbl_secattr_free(ssec->nlbl_secattr);
+}
+
 /**
  * selinux_netlbl_sk_security_reset - Reset the NetLabel fields
  * @ssec: the sk_security_struct
@@ -163,35 +236,118 @@ int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
 }
 
 /**
- * selinux_netlbl_sock_graft - Netlabel the new socket
+ * selinux_netlbl_skbuff_setsid - Set the NetLabel on a packet given a sid
+ * @skb: the packet
+ * @family: protocol family
+ * @sid: the SID
+ *
+ * Description
+ * Call the NetLabel mechanism to set the label of a packet using @sid.
+ * Returns zero on auccess, negative values on failure.
+ *
+ */
+int selinux_netlbl_skbuff_setsid(struct sk_buff *skb,
+                                u16 family,
+                                u32 sid)
+{
+       int rc;
+       struct netlbl_lsm_secattr secattr_storage;
+       struct netlbl_lsm_secattr *secattr = NULL;
+       struct sock *sk;
+
+       /* if this is a locally generated packet check to see if it is already
+        * being labeled by it's parent socket, if it is just exit */
+       sk = skb->sk;
+       if (sk != NULL) {
+               struct sk_security_struct *sksec = sk->sk_security;
+               if (sksec->nlbl_state != NLBL_REQSKB)
+                       return 0;
+               secattr = sksec->nlbl_secattr;
+       }
+       if (secattr == NULL) {
+               secattr = &secattr_storage;
+               netlbl_secattr_init(secattr);
+               rc = security_netlbl_sid_to_secattr(sid, secattr);
+               if (rc != 0)
+                       goto skbuff_setsid_return;
+       }
+
+       rc = netlbl_skbuff_setattr(skb, family, secattr);
+
+skbuff_setsid_return:
+       if (secattr == &secattr_storage)
+               netlbl_secattr_destroy(secattr);
+       return rc;
+}
+
+/**
+ * selinux_netlbl_inet_conn_established - Netlabel the newly accepted connection
  * @sk: the new connection
- * @sock: the new socket
  *
  * Description:
- * The connection represented by @sk is being grafted onto @sock so set the
- * socket's NetLabel to match the SID of @sk.
+ * A new connection has been established on @sk so make sure it is labeled
+ * correctly with the NetLabel susbsystem.
  *
  */
-void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock)
+void selinux_netlbl_inet_conn_established(struct sock *sk, u16 family)
 {
+       int rc;
        struct sk_security_struct *sksec = sk->sk_security;
-       struct netlbl_lsm_secattr secattr;
-       u32 nlbl_peer_sid;
+       struct netlbl_lsm_secattr *secattr;
+       struct inet_sock *sk_inet = inet_sk(sk);
+       struct sockaddr_in addr;
 
        if (sksec->nlbl_state != NLBL_REQUIRE)
                return;
 
-       netlbl_secattr_init(&secattr);
-       if (netlbl_sock_getattr(sk, &secattr) == 0 &&
-           secattr.flags != NETLBL_SECATTR_NONE &&
-           security_netlbl_secattr_to_sid(&secattr, &nlbl_peer_sid) == 0)
-               sksec->peer_sid = nlbl_peer_sid;
-       netlbl_secattr_destroy(&secattr);
+       secattr = selinux_netlbl_sock_genattr(sk);
+       if (secattr == NULL)
+               return;
 
-       /* Try to set the NetLabel on the socket to save time later, if we fail
-        * here we will pick up the pieces in later calls to
-        * selinux_netlbl_inode_permission(). */
-       selinux_netlbl_sock_setsid(sk, sksec->sid);
+       rc = netlbl_sock_setattr(sk, secattr);
+       switch (rc) {
+       case 0:
+               sksec->nlbl_state = NLBL_LABELED;
+               break;
+       case -EDESTADDRREQ:
+               /* no PF_INET6 support yet because we don't support any IPv6
+                * labeling protocols */
+               if (family != PF_INET) {
+                       sksec->nlbl_state = NLBL_UNSET;
+                       return;
+               }
+
+               addr.sin_family = family;
+               addr.sin_addr.s_addr = sk_inet->daddr;
+               if (netlbl_conn_setattr(sk, (struct sockaddr *)&addr,
+                                       secattr) != 0) {
+                       /* we failed to label the connected socket (could be
+                        * for a variety of reasons, the actual "why" isn't
+                        * important here) so we have to go to our backup plan,
+                        * labeling the packets individually in the netfilter
+                        * local output hook.  this is okay but we need to
+                        * adjust the MSS of the connection to take into
+                        * account any labeling overhead, since we don't know
+                        * the exact overhead at this point we'll use the worst
+                        * case value which is 40 bytes for IPv4 */
+                       struct inet_connection_sock *sk_conn = inet_csk(sk);
+                       sk_conn->icsk_ext_hdr_len += 40 -
+                                     (sk_inet->opt ? sk_inet->opt->optlen : 0);
+                       sk_conn->icsk_sync_mss(sk, sk_conn->icsk_pmtu_cookie);
+
+                       sksec->nlbl_state = NLBL_REQSKB;
+               } else
+                       sksec->nlbl_state = NLBL_CONNLABELED;
+               break;
+       default:
+               /* note that we are failing to label the socket which could be
+                * a bad thing since it means traffic could leave the system
+                * without the desired labeling, however, all is not lost as
+                * we have a check in selinux_netlbl_inode_permission() to
+                * pick up the pieces that we might drop here because we can't
+                * return an error code */
+               break;
+       }
 }
 
 /**
@@ -205,13 +361,7 @@ void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock)
  */
 int selinux_netlbl_socket_post_create(struct socket *sock)
 {
-       struct sock *sk = sock->sk;
-       struct sk_security_struct *sksec = sk->sk_security;
-
-       if (sksec->nlbl_state != NLBL_REQUIRE)
-               return 0;
-
-       return selinux_netlbl_sock_setsid(sk, sksec->sid);
+       return selinux_netlbl_sock_setsid(sock->sk);
 }
 
 /**
@@ -246,7 +396,7 @@ int selinux_netlbl_inode_permission(struct inode *inode, int mask)
        local_bh_disable();
        bh_lock_sock_nested(sk);
        if (likely(sksec->nlbl_state == NLBL_REQUIRE))
-               rc = selinux_netlbl_sock_setsid(sk, sksec->sid);
+               rc = selinux_netlbl_sock_setsid(sk);
        else
                rc = 0;
        bh_unlock_sock(sk);
@@ -307,7 +457,7 @@ int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
                return 0;
 
        if (nlbl_sid != SECINITSID_UNLABELED)
-               netlbl_skbuff_err(skb, rc);
+               netlbl_skbuff_err(skb, rc, 0);
        return rc;
 }
 
@@ -334,7 +484,8 @@ int selinux_netlbl_socket_setsockopt(struct socket *sock,
        struct netlbl_lsm_secattr secattr;
 
        if (level == IPPROTO_IP && optname == IP_OPTIONS &&
-           sksec->nlbl_state == NLBL_LABELED) {
+           (sksec->nlbl_state == NLBL_LABELED ||
+            sksec->nlbl_state == NLBL_CONNLABELED)) {
                netlbl_secattr_init(&secattr);
                lock_sock(sk);
                rc = netlbl_sock_getattr(sk, &secattr);
@@ -346,3 +497,50 @@ int selinux_netlbl_socket_setsockopt(struct socket *sock,
 
        return rc;
 }
+
+/**
+ * selinux_netlbl_socket_connect - Label a client-side socket on connect
+ * @sk: the socket to label
+ * @addr: the destination address
+ *
+ * Description:
+ * Attempt to label a connected socket with NetLabel using the given address.
+ * Returns zero values on success, negative values on failure.
+ *
+ */
+int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr)
+{
+       int rc;
+       struct sk_security_struct *sksec = sk->sk_security;
+       struct netlbl_lsm_secattr *secattr;
+
+       if (sksec->nlbl_state != NLBL_REQSKB &&
+           sksec->nlbl_state != NLBL_CONNLABELED)
+               return 0;
+
+       local_bh_disable();
+       bh_lock_sock_nested(sk);
+
+       /* connected sockets are allowed to disconnect when the address family
+        * is set to AF_UNSPEC, if that is what is happening we want to reset
+        * the socket */
+       if (addr->sa_family == AF_UNSPEC) {
+               netlbl_sock_delattr(sk);
+               sksec->nlbl_state = NLBL_REQSKB;
+               rc = 0;
+               goto socket_connect_return;
+       }
+       secattr = selinux_netlbl_sock_genattr(sk);
+       if (secattr == NULL) {
+               rc = -ENOMEM;
+               goto socket_connect_return;
+       }
+       rc = netlbl_conn_setattr(sk, addr, secattr);
+       if (rc == 0)
+               sksec->nlbl_state = NLBL_CONNLABELED;
+
+socket_connect_return:
+       bh_unlock_sock(sk);
+       local_bh_enable();
+       return rc;
+}
index ab0cc0c7b9444e60a8cf625c0edb1aaa479456ba..343c8ab14af0a71881336ac3c2461d3360839895 100644 (file)
@@ -2955,7 +2955,7 @@ netlbl_secattr_to_sid_return_cleanup:
  */
 int security_netlbl_sid_to_secattr(u32 sid, struct netlbl_lsm_secattr *secattr)
 {
-       int rc = -ENOENT;
+       int rc;
        struct context *ctx;
 
        if (!ss_initialized)
@@ -2963,11 +2963,18 @@ int security_netlbl_sid_to_secattr(u32 sid, struct netlbl_lsm_secattr *secattr)
 
        read_lock(&policy_rwlock);
        ctx = sidtab_search(&sidtab, sid);
-       if (ctx == NULL)
+       if (ctx == NULL) {
+               rc = -ENOENT;
                goto netlbl_sid_to_secattr_failure;
+       }
        secattr->domain = kstrdup(policydb.p_type_val_to_name[ctx->type - 1],
                                  GFP_ATOMIC);
-       secattr->flags |= NETLBL_SECATTR_DOMAIN_CPY;
+       if (secattr->domain == NULL) {
+               rc = -ENOMEM;
+               goto netlbl_sid_to_secattr_failure;
+       }
+       secattr->attr.secid = sid;
+       secattr->flags |= NETLBL_SECATTR_DOMAIN_CPY | NETLBL_SECATTR_SECID;
        mls_export_netlbl_lvl(ctx, secattr);
        rc = mls_export_netlbl_cat(ctx, secattr);
        if (rc != 0)
index 87d75417ea937e7756678fd381c3cb96c9d1c7a5..6e2dc0bab70d837a57ac78a452603178761fbbb3 100644 (file)
@@ -2179,7 +2179,10 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
         * This is the simplist possible security model
         * for networking.
         */
-       return smk_access(smack, ssp->smk_in, MAY_WRITE);
+       rc = smk_access(smack, ssp->smk_in, MAY_WRITE);
+       if (rc != 0)
+               netlbl_skbuff_err(skb, rc, 0);
+       return rc;
 }
 
 /**
index e7c642458ec9431b1639935880b6082f21492f6a..c21d8c8bf0c789f3af9693fac3cdbd226dd4b8cc 100644 (file)
@@ -354,9 +354,11 @@ static void smk_cipso_doi(void)
                doip->tags[rc] = CIPSO_V4_TAG_INVALID;
 
        rc = netlbl_cfg_cipsov4_add_map(doip, NULL, &audit_info);
-       if (rc != 0)
+       if (rc != 0) {
                printk(KERN_WARNING "%s:%d add rc = %d\n",
                       __func__, __LINE__, rc);
+               kfree(doip);
+       }
 }
 
 /**
index b63839e8f9bd13c344c1efdcf6f45d7eff434b94..456a1b4d7832222b577d43e14dcde7b3baba2c9c 100644 (file)
@@ -30,7 +30,7 @@
  **************************************************************************
  *
  * History
- * May 02, 2003 Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ * May 02, 2003 Liam Girdwood <lrg@slimlogic.co.uk>
  *     Removed non existant WM9700
  *     Added support for WM9705, WM9708, WM9709, WM9710, WM9711
  *     WM9712 and WM9717
index 6ce3cbe98a6a11d7212cfca404a01a73f6bf26bd..6e831aff1bd0e50ae3f38bc6484c0688b6084632 100644 (file)
@@ -476,7 +476,7 @@ static int patch_yamaha_ymf753(struct snd_ac97 * ac97)
 }
 
 /*
- * May 2, 2003 Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ * May 2, 2003 Liam Girdwood <lrg@slimlogic.co.uk>
  *  removed broken wolfson00 patch.
  *  added support for WM9705,WM9708,WM9709,WM9710,WM9711,WM9712 and WM9717.
  */
index c461baa83c2a9ead2c669bc86460215340bbe4aa..c5906551311895285782942e49a92ca43c608f06 100644 (file)
@@ -322,8 +322,8 @@ static hda_nid_t stac92hd71bxx_mux_nids[2] = {
        0x1a, 0x1b
 };
 
-static hda_nid_t stac92hd71bxx_dmux_nids[1] = {
-       0x1c,
+static hda_nid_t stac92hd71bxx_dmux_nids[2] = {
+       0x1c, 0x1d,
 };
 
 static hda_nid_t stac92hd71bxx_smux_nids[2] = {
@@ -861,20 +861,18 @@ static struct hda_verb stac92hd71bxx_core_init[] = {
        { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
        /* connect headphone jack to dac1 */
        { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
-       { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */
        /* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */
        { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
        { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
        { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 };
 
-#define HD_DISABLE_PORTF 3
+#define HD_DISABLE_PORTF 2
 static struct hda_verb stac92hd71bxx_analog_core_init[] = {
        /* start of config #1 */
 
        /* connect port 0f to audio mixer */
        { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2},
-       { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */
        /* unmute right and left channels for node 0x0f */
        { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
        /* start of config #2 */
@@ -883,10 +881,6 @@ static struct hda_verb stac92hd71bxx_analog_core_init[] = {
        { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
        /* connect headphone jack to dac1 */
        { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
-       /* connect port 0d to audio mixer */
-       { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x2},
-       /* unmute dac0 input in audio mixer */
-       { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f},
        /* unmute right and left channels for nodes 0x0a, 0xd */
        { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
        { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
@@ -1107,6 +1101,7 @@ static struct snd_kcontrol_new stac92hd83xxx_mixer[] = {
 
 static struct snd_kcontrol_new stac92hd71bxx_analog_mixer[] = {
        STAC_INPUT_SOURCE(2),
+       STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2),
 
        HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
@@ -1119,8 +1114,17 @@ static struct snd_kcontrol_new stac92hd71bxx_analog_mixer[] = {
        HDA_CODEC_MUTE("PC Beep Switch", 0x17, 0x2, HDA_INPUT),
        */
 
-       HDA_CODEC_MUTE("Analog Loopback 1", 0x17, 0x3, HDA_INPUT),
-       HDA_CODEC_MUTE("Analog Loopback 2", 0x17, 0x4, HDA_INPUT),
+       HDA_CODEC_MUTE("Import0 Mux Capture Switch", 0x17, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Import0 Mux Capture Volume", 0x17, 0x0, HDA_INPUT),
+
+       HDA_CODEC_MUTE("Import1 Mux Capture Switch", 0x17, 0x1, HDA_INPUT),
+       HDA_CODEC_VOLUME("Import1 Mux Capture Volume", 0x17, 0x1, HDA_INPUT),
+
+       HDA_CODEC_MUTE("DAC0 Capture Switch", 0x17, 0x3, HDA_INPUT),
+       HDA_CODEC_VOLUME("DAC0 Capture Volume", 0x17, 0x3, HDA_INPUT),
+
+       HDA_CODEC_MUTE("DAC1 Capture Switch", 0x17, 0x4, HDA_INPUT),
+       HDA_CODEC_VOLUME("DAC1 Capture Volume", 0x17, 0x4, HDA_INPUT),
        { } /* end */
 };
 
@@ -1649,7 +1653,7 @@ static struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = {
 
 static unsigned int ref92hd71bxx_pin_configs[11] = {
        0x02214030, 0x02a19040, 0x01a19020, 0x01014010,
-       0x0181302e, 0x01114010, 0x01019020, 0x90a000f0,
+       0x0181302e, 0x01014010, 0x01019020, 0x90a000f0,
        0x90a000f0, 0x01452050, 0x01452050,
 };
 
@@ -3000,7 +3004,7 @@ static int stac92xx_auto_create_mono_output_ctls(struct hda_codec *codec)
 
 /* labels for amp mux outputs */
 static const char *stac92xx_amp_labels[3] = {
-       "Front Microphone", "Microphone", "Line In"
+       "Front Microphone", "Microphone", "Line In",
 };
 
 /* create amp out controls mux on capable codecs */
@@ -4327,6 +4331,16 @@ static struct hda_codec_ops stac92hd71bxx_patch_ops = {
 #endif
 };
 
+static struct hda_input_mux stac92hd71bxx_dmux = {
+       .num_items = 4,
+       .items = {
+               { "Analog Inputs", 0x00 },
+               { "Mixer", 0x01 },
+               { "Digital Mic 1", 0x02 },
+               { "Digital Mic 2", 0x03 },
+       }
+};
+
 static int patch_stac92hd71bxx(struct hda_codec *codec)
 {
        struct sigmatel_spec *spec;
@@ -4341,6 +4355,8 @@ static int patch_stac92hd71bxx(struct hda_codec *codec)
        spec->num_pins = ARRAY_SIZE(stac92hd71bxx_pin_nids);
        spec->num_pwrs = ARRAY_SIZE(stac92hd71bxx_pwr_nids);
        spec->pin_nids = stac92hd71bxx_pin_nids;
+       memcpy(&spec->private_dimux, &stac92hd71bxx_dmux,
+                       sizeof(stac92hd71bxx_dmux));
        spec->board_config = snd_hda_check_board_config(codec,
                                                        STAC_92HD71BXX_MODELS,
                                                        stac92hd71bxx_models,
@@ -4392,6 +4408,7 @@ again:
                /* no output amps */
                spec->num_pwrs = 0;
                spec->mixer = stac92hd71bxx_analog_mixer;
+               spec->dinput_mux = &spec->private_dimux;
 
                /* disable VSW */
                spec->init = &stac92hd71bxx_analog_core_init[HD_DISABLE_PORTF];
@@ -4409,12 +4426,13 @@ again:
                spec->num_pwrs = 0;
                /* fallthru */
        default:
+               spec->dinput_mux = &spec->private_dimux;
                spec->mixer = stac92hd71bxx_analog_mixer;
                spec->init = stac92hd71bxx_analog_core_init;
                codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs;
        }
 
-       spec->aloopback_mask = 0x20;
+       spec->aloopback_mask = 0x50;
        spec->aloopback_shift = 0;
 
        if (spec->board_config > STAC_92HD71BXX_REF) {
@@ -4456,6 +4474,10 @@ again:
        spec->multiout.num_dacs = 1;
        spec->multiout.hp_nid = 0x11;
        spec->multiout.dac_nids = stac92hd71bxx_dac_nids;
+       if (spec->dinput_mux)
+               spec->private_dimux.num_items +=
+                       spec->num_dmics -
+                               (ARRAY_SIZE(stac92hd71bxx_dmic_nids) - 1);
 
        err = stac92xx_parse_auto_config(codec, 0x21, 0x23);
        if (!err) {
index 905186502e0009039efc81919022b9d4ffe44a54..85a883299c2e5dc10c72182f1e6a2d903c15d7dd 100644 (file)
@@ -8,20 +8,3 @@ config SND_AT91_SOC
 
 config SND_AT91_SOC_SSC
        tristate
-
-config SND_AT91_SOC_ETI_B1_WM8731
-       tristate "SoC Audio support for WM8731-based Endrelia ETI-B1 boards"
-       depends on SND_AT91_SOC && (MACH_ETI_B1 || MACH_ETI_C1)
-       select SND_AT91_SOC_SSC
-       select SND_SOC_WM8731
-       help
-         Say Y if you want to add support for SoC audio on WM8731-based
-         Endrelia Technologies Inc ETI-B1 or ETI-C1 boards.
-
-config SND_AT91_SOC_ETI_SLAVE
-       bool "Run codec in slave Mode on Endrelia boards"
-       depends on SND_AT91_SOC_ETI_B1_WM8731
-       default n
-       help
-         Say Y if you want to run with the AT91 SSC generating the BCLK
-         and LRC signals on Endrelia boards.
index f23da17cc3288e0e11ac2e951ffcf2a14b3e87bd..b817f11df28669be198c3e3743a535b98e4a5aec 100644 (file)
@@ -4,8 +4,3 @@ snd-soc-at91-ssc-objs := at91-ssc.o
 
 obj-$(CONFIG_SND_AT91_SOC) += snd-soc-at91.o
 obj-$(CONFIG_SND_AT91_SOC_SSC) += snd-soc-at91-ssc.o
-
-# AT91 Machine Support
-snd-soc-eti-b1-wm8731-objs := eti_b1_wm8731.o
-
-obj-$(CONFIG_SND_AT91_SOC_ETI_B1_WM8731) += snd-soc-eti-b1-wm8731.o
index a5b1a79ebffb5f72968ac949546bd59b1ae2dc5f..1b61cc4612618eedc61434fa23f559d54a0e4d3a 100644 (file)
@@ -5,7 +5,7 @@
  *         Endrelia Technologies Inc.
  *
  * Based on pxa2xx Platform drivers by
- * Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ * Liam Girdwood <lrg@slimlogic.co.uk>
  *
  *  This program is free software; you can redistribute  it and/or modify it
  *  under  the terms of  the GNU General  Public License as published by the
diff --git a/sound/soc/at91/eti_b1_wm8731.c b/sound/soc/at91/eti_b1_wm8731.c
deleted file mode 100644 (file)
index 684781e..0000000
+++ /dev/null
@@ -1,349 +0,0 @@
-/*
- * eti_b1_wm8731  --  SoC audio for AT91RM9200-based Endrelia ETI_B1 board.
- *
- * Author:     Frank Mandarino <fmandarino@endrelia.com>
- *             Endrelia Technologies Inc.
- * Created:    Mar 29, 2006
- *
- * Based on corgi.c by:
- *
- * Copyright 2005 Wolfson Microelectronics PLC.
- * Copyright 2005 Openedhand Ltd.
- *
- * Authors: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
- *          Richard Purdie <richard@openedhand.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.
- *
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/kernel.h>
-#include <linux/clk.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-#include <sound/soc-dapm.h>
-
-#include <mach/hardware.h>
-#include <mach/gpio.h>
-
-#include "../codecs/wm8731.h"
-#include "at91-pcm.h"
-#include "at91-ssc.h"
-
-#if 0
-#define        DBG(x...)       printk(KERN_INFO "eti_b1_wm8731: " x)
-#else
-#define        DBG(x...)
-#endif
-
-static struct clk *pck1_clk;
-static struct clk *pllb_clk;
-
-
-static int eti_b1_startup(struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
-       int ret;
-
-       /* cpu clock is the AT91 master clock sent to the SSC */
-       ret = snd_soc_dai_set_sysclk(cpu_dai, AT91_SYSCLK_MCK,
-               60000000, SND_SOC_CLOCK_IN);
-       if (ret < 0)
-               return ret;
-
-       /* codec system clock is supplied by PCK1, set to 12MHz */
-       ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK,
-               12000000, SND_SOC_CLOCK_IN);
-       if (ret < 0)
-               return ret;
-
-       /* Start PCK1 clock. */
-       clk_enable(pck1_clk);
-       DBG("pck1 started\n");
-
-       return 0;
-}
-
-static void eti_b1_shutdown(struct snd_pcm_substream *substream)
-{
-       /* Stop PCK1 clock. */
-       clk_disable(pck1_clk);
-       DBG("pck1 stopped\n");
-}
-
-static int eti_b1_hw_params(struct snd_pcm_substream *substream,
-       struct snd_pcm_hw_params *params)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
-       int ret;
-
-#ifdef CONFIG_SND_AT91_SOC_ETI_SLAVE
-       unsigned int rate;
-       int cmr_div, period;
-
-       /* set codec DAI configuration */
-       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
-               SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
-       /* set cpu DAI configuration */
-       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
-               SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
-       /*
-        * The SSC clock dividers depend on the sample rate.  The CMR.DIV
-        * field divides the system master clock MCK to drive the SSC TK
-        * signal which provides the codec BCLK.  The TCMR.PERIOD and
-        * RCMR.PERIOD fields further divide the BCLK signal to drive
-        * the SSC TF and RF signals which provide the codec DACLRC and
-        * ADCLRC clocks.
-        *
-        * The dividers were determined through trial and error, where a
-        * CMR.DIV value is chosen such that the resulting BCLK value is
-        * divisible, or almost divisible, by (2 * sample rate), and then
-        * the TCMR.PERIOD or RCMR.PERIOD is BCLK / (2 * sample rate) - 1.
-        */
-       rate = params_rate(params);
-
-       switch (rate) {
-       case 8000:
-               cmr_div = 25;   /* BCLK = 60MHz/(2*25) = 1.2MHz */
-               period = 74;    /* LRC = BCLK/(2*(74+1)) = 8000Hz */
-               break;
-       case 32000:
-               cmr_div = 7;    /* BCLK = 60MHz/(2*7) ~= 4.28571428MHz */
-               period = 66;    /* LRC = BCLK/(2*(66+1)) = 31982.942Hz */
-               break;
-       case 48000:
-               cmr_div = 13;   /* BCLK = 60MHz/(2*13) ~= 2.3076923MHz */
-               period = 23;    /* LRC = BCLK/(2*(23+1)) = 48076.923Hz */
-               break;
-       default:
-               printk(KERN_WARNING "unsupported rate %d on ETI-B1 board\n", rate);
-               return -EINVAL;
-       }
-
-       /* set the MCK divider for BCLK */
-       ret = snd_soc_dai_set_clkdiv(cpu_dai, AT91SSC_CMR_DIV, cmr_div);
-       if (ret < 0)
-               return ret;
-
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               /* set the BCLK divider for DACLRC */
-               ret = snd_soc_dai_set_clkdiv(cpu_dai,
-                                               AT91SSC_TCMR_PERIOD, period);
-       } else {
-               /* set the BCLK divider for ADCLRC */
-               ret = snd_soc_dai_set_clkdiv(cpu_dai,
-                                               AT91SSC_RCMR_PERIOD, period);
-       }
-       if (ret < 0)
-               return ret;
-
-#else /* CONFIG_SND_AT91_SOC_ETI_SLAVE */
-       /*
-        * Codec in Master Mode.
-        */
-
-       /* set codec DAI configuration */
-       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
-               SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
-       if (ret < 0)
-               return ret;
-
-       /* set cpu DAI configuration */
-       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
-               SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
-       if (ret < 0)
-               return ret;
-
-#endif /* CONFIG_SND_AT91_SOC_ETI_SLAVE */
-
-       return 0;
-}
-
-static struct snd_soc_ops eti_b1_ops = {
-       .startup = eti_b1_startup,
-       .hw_params = eti_b1_hw_params,
-       .shutdown = eti_b1_shutdown,
-};
-
-
-static const struct snd_soc_dapm_widget eti_b1_dapm_widgets[] = {
-       SND_SOC_DAPM_MIC("Int Mic", NULL),
-       SND_SOC_DAPM_SPK("Ext Spk", NULL),
-};
-
-static const struct snd_soc_dapm_route intercon[] = {
-
-       /* speaker connected to LHPOUT */
-       {"Ext Spk", NULL, "LHPOUT"},
-
-       /* mic is connected to Mic Jack, with WM8731 Mic Bias */
-       {"MICIN", NULL, "Mic Bias"},
-       {"Mic Bias", NULL, "Int Mic"},
-};
-
-/*
- * Logic for a wm8731 as connected on a Endrelia ETI-B1 board.
- */
-static int eti_b1_wm8731_init(struct snd_soc_codec *codec)
-{
-       DBG("eti_b1_wm8731_init() called\n");
-
-       /* Add specific widgets */
-       snd_soc_dapm_new_controls(codec, eti_b1_dapm_widgets,
-                                 ARRAY_SIZE(eti_b1_dapm_widgets));
-
-       /* Set up specific audio path interconnects */
-       snd_soc_dapm_add_route(codec, intercon, ARRAY_SIZE(intercon));
-
-       /* not connected */
-       snd_soc_dapm_disable_pin(codec, "RLINEIN");
-       snd_soc_dapm_disable_pin(codec, "LLINEIN");
-
-       /* always connected */
-       snd_soc_dapm_enable_pin(codec, "Int Mic");
-       snd_soc_dapm_enable_pin(codec, "Ext Spk");
-
-       snd_soc_dapm_sync(codec);
-
-       return 0;
-}
-
-static struct snd_soc_dai_link eti_b1_dai = {
-       .name = "WM8731",
-       .stream_name = "WM8731 PCM",
-       .cpu_dai = &at91_ssc_dai[1],
-       .codec_dai = &wm8731_dai,
-       .init = eti_b1_wm8731_init,
-       .ops = &eti_b1_ops,
-};
-
-static struct snd_soc_machine snd_soc_machine_eti_b1 = {
-       .name = "ETI_B1_WM8731",
-       .dai_link = &eti_b1_dai,
-       .num_links = 1,
-};
-
-static struct wm8731_setup_data eti_b1_wm8731_setup = {
-       .i2c_bus = 0,
-       .i2c_address = 0x1a,
-};
-
-static struct snd_soc_device eti_b1_snd_devdata = {
-       .machine = &snd_soc_machine_eti_b1,
-       .platform = &at91_soc_platform,
-       .codec_dev = &soc_codec_dev_wm8731,
-       .codec_data = &eti_b1_wm8731_setup,
-};
-
-static struct platform_device *eti_b1_snd_device;
-
-static int __init eti_b1_init(void)
-{
-       int ret;
-       struct at91_ssc_periph *ssc = eti_b1_dai.cpu_dai->private_data;
-
-       if (!request_mem_region(AT91RM9200_BASE_SSC1, SZ_16K, "soc-audio")) {
-               DBG("SSC1 memory region is busy\n");
-               return -EBUSY;
-       }
-
-       ssc->base = ioremap(AT91RM9200_BASE_SSC1, SZ_16K);
-       if (!ssc->base) {
-               DBG("SSC1 memory ioremap failed\n");
-               ret = -ENOMEM;
-               goto fail_release_mem;
-       }
-
-       ssc->pid = AT91RM9200_ID_SSC1;
-
-       eti_b1_snd_device = platform_device_alloc("soc-audio", -1);
-       if (!eti_b1_snd_device) {
-               DBG("platform device allocation failed\n");
-               ret = -ENOMEM;
-               goto fail_io_unmap;
-       }
-
-       platform_set_drvdata(eti_b1_snd_device, &eti_b1_snd_devdata);
-       eti_b1_snd_devdata.dev = &eti_b1_snd_device->dev;
-
-       ret = platform_device_add(eti_b1_snd_device);
-       if (ret) {
-               DBG("platform device add failed\n");
-               platform_device_put(eti_b1_snd_device);
-               goto fail_io_unmap;
-       }
-
-       at91_set_A_periph(AT91_PIN_PB6, 0);     /* TF1 */
-       at91_set_A_periph(AT91_PIN_PB7, 0);     /* TK1 */
-       at91_set_A_periph(AT91_PIN_PB8, 0);     /* TD1 */
-       at91_set_A_periph(AT91_PIN_PB9, 0);     /* RD1 */
-/*     at91_set_A_periph(AT91_PIN_PB10, 0);*/  /* RK1 */
-       at91_set_A_periph(AT91_PIN_PB11, 0);    /* RF1 */
-
-       /*
-        * Set PCK1 parent to PLLB and its rate to 12 Mhz.
-        */
-       pllb_clk = clk_get(NULL, "pllb");
-       pck1_clk = clk_get(NULL, "pck1");
-
-       clk_set_parent(pck1_clk, pllb_clk);
-       clk_set_rate(pck1_clk, 12000000);
-
-       DBG("MCLK rate %luHz\n", clk_get_rate(pck1_clk));
-
-       /* assign the GPIO pin to PCK1 */
-       at91_set_B_periph(AT91_PIN_PA24, 0);
-
-#ifdef CONFIG_SND_AT91_SOC_ETI_SLAVE
-       printk(KERN_INFO "eti_b1_wm8731: Codec in Slave Mode\n");
-#else
-       printk(KERN_INFO "eti_b1_wm8731: Codec in Master Mode\n");
-#endif
-       return ret;
-
-fail_io_unmap:
-       iounmap(ssc->base);
-fail_release_mem:
-       release_mem_region(AT91RM9200_BASE_SSC1, SZ_16K);
-       return ret;
-}
-
-static void __exit eti_b1_exit(void)
-{
-       struct at91_ssc_periph *ssc = eti_b1_dai.cpu_dai->private_data;
-
-       clk_put(pck1_clk);
-       clk_put(pllb_clk);
-
-       platform_device_unregister(eti_b1_snd_device);
-
-       iounmap(ssc->base);
-       release_mem_region(AT91RM9200_BASE_SSC1, SZ_16K);
-}
-
-module_init(eti_b1_init);
-module_exit(eti_b1_exit);
-
-/* Module information */
-MODULE_AUTHOR("Frank Mandarino <fmandarino@endrelia.com>");
-MODULE_DESCRIPTION("ALSA SoC ETI-B1-WM8731");
-MODULE_LICENSE("GPL");
index f98331d099e7f05379b70dd1080f4477a4c7f39c..dc006206f622d043d4257162e71466f3b77bf0fb 100644 (file)
@@ -17,6 +17,22 @@ config SND_BF5XX_SOC_SSM2602
        help
          Say Y if you want to add support for SoC audio on BF527-EZKIT.
 
+config SND_BF5XX_SOC_AD73311
+       tristate "SoC AD73311 Audio support for Blackfin"
+       depends on SND_BF5XX_I2S
+       select SND_BF5XX_SOC_I2S
+       select SND_SOC_AD73311
+       help
+         Say Y if you want to add support for AD73311 codec on Blackfin.
+
+config SND_BFIN_AD73311_SE
+       int "PF pin for AD73311L Chip Select"
+       depends on SND_BF5XX_SOC_AD73311
+       default 4
+       help
+         Enter the GPIO used to control AD73311's SE pin. Acceptable
+         values are 0 to 7
+
 config SND_BF5XX_AC97
        tristate "SoC AC97 Audio for the ADI BF5xx chip"
        depends on BLACKFIN && SND_SOC
index 9ea8bd9e0ba3448471fdbfc3b52b7d76c27eb9b8..97bb37a6359c9b72816424658fdab4636c76fa36 100644 (file)
@@ -14,7 +14,8 @@ obj-$(CONFIG_SND_BF5XX_SOC_I2S) += snd-soc-bf5xx-i2s.o
 # Blackfin Machine Support
 snd-ad1980-objs := bf5xx-ad1980.o
 snd-ssm2602-objs := bf5xx-ssm2602.o
-
+snd-ad73311-objs := bf5xx-ad73311.o
 
 obj-$(CONFIG_SND_BF5XX_SOC_AD1980) += snd-ad1980.o
 obj-$(CONFIG_SND_BF5XX_SOC_SSM2602) += snd-ssm2602.o
+obj-$(CONFIG_SND_BF5XX_SOC_AD73311) += snd-ad73311.o
index 51f4907c4831af2f86fb04aa4a3c7fa5b10e22d2..25e50d2ea1ec321d4140295f6d6ce587d79f0a9a 100644 (file)
@@ -56,6 +56,7 @@ static void bf5xx_mmap_copy(struct snd_pcm_substream *substream,
                sport->tx_pos += runtime->period_size;
                if (sport->tx_pos >= runtime->buffer_size)
                        sport->tx_pos %= runtime->buffer_size;
+               sport->tx_delay_pos = sport->tx_pos;
        } else {
                bf5xx_ac97_to_pcm(
                        (struct ac97_frame *)sport->rx_dma_buf + sport->rx_pos,
@@ -72,7 +73,15 @@ static void bf5xx_dma_irq(void *data)
        struct snd_pcm_substream *pcm = data;
 #if defined(CONFIG_SND_MMAP_SUPPORT)
        struct snd_pcm_runtime *runtime = pcm->runtime;
+       struct sport_device *sport = runtime->private_data;
        bf5xx_mmap_copy(pcm, runtime->period_size);
+       if (pcm->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               if (sport->once == 0) {
+                       snd_pcm_period_elapsed(pcm);
+                       bf5xx_mmap_copy(pcm, runtime->period_size);
+                       sport->once = 1;
+               }
+       }
 #endif
        snd_pcm_period_elapsed(pcm);
 }
@@ -114,6 +123,10 @@ static int bf5xx_pcm_hw_params(struct snd_pcm_substream *substream,
 
 static int bf5xx_pcm_hw_free(struct snd_pcm_substream *substream)
 {
+       struct snd_pcm_runtime *runtime = substream->runtime;
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+       memset(runtime->dma_area, 0, runtime->buffer_size);
        snd_pcm_lib_free_pages(substream);
        return 0;
 }
@@ -127,16 +140,11 @@ static int bf5xx_pcm_prepare(struct snd_pcm_substream *substream)
         * SPORT working in TMD mode(include AC97).
         */
 #if defined(CONFIG_SND_MMAP_SUPPORT)
-       size_t size = bf5xx_pcm_hardware.buffer_bytes_max
-                       * sizeof(struct ac97_frame) / 4;
-       /*clean up intermediate buffer*/
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               memset(sport->tx_dma_buf, 0, size);
                sport_set_tx_callback(sport, bf5xx_dma_irq, substream);
                sport_config_tx_dma(sport, sport->tx_dma_buf, runtime->periods,
                        runtime->period_size * sizeof(struct ac97_frame));
        } else {
-               memset(sport->rx_dma_buf, 0, size);
                sport_set_rx_callback(sport, bf5xx_dma_irq, substream);
                sport_config_rx_dma(sport, sport->rx_dma_buf, runtime->periods,
                        runtime->period_size * sizeof(struct ac97_frame));
@@ -164,8 +172,12 @@ static int bf5xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
        pr_debug("%s enter\n", __func__);
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
-               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+                       bf5xx_mmap_copy(substream, runtime->period_size);
+                       snd_pcm_period_elapsed(substream);
+                       sport->tx_delay_pos = 0;
                        sport_tx_start(sport);
+               }
                else
                        sport_rx_start(sport);
                break;
@@ -198,7 +210,7 @@ static snd_pcm_uframes_t bf5xx_pcm_pointer(struct snd_pcm_substream *substream)
 
 #if defined(CONFIG_SND_MMAP_SUPPORT)
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               curr = sport->tx_pos;
+               curr = sport->tx_delay_pos;
        else
                curr = sport->rx_pos;
 #else
@@ -237,6 +249,21 @@ static int bf5xx_pcm_open(struct snd_pcm_substream *substream)
        return ret;
 }
 
+static int bf5xx_pcm_close(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct sport_device *sport = runtime->private_data;
+
+       pr_debug("%s enter\n", __func__);
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               sport->once = 0;
+               memset(sport->tx_dma_buf, 0, runtime->buffer_size * sizeof(struct ac97_frame));
+       } else
+               memset(sport->rx_dma_buf, 0, runtime->buffer_size * sizeof(struct ac97_frame));
+
+       return 0;
+}
+
 #ifdef CONFIG_SND_MMAP_SUPPORT
 static int bf5xx_pcm_mmap(struct snd_pcm_substream *substream,
        struct vm_area_struct *vma)
@@ -272,6 +299,7 @@ static      int bf5xx_pcm_copy(struct snd_pcm_substream *substream, int channel,
 
 struct snd_pcm_ops bf5xx_pcm_ac97_ops = {
        .open           = bf5xx_pcm_open,
+       .close          = bf5xx_pcm_close,
        .ioctl          = snd_pcm_lib_ioctl,
        .hw_params      = bf5xx_pcm_hw_params,
        .hw_free        = bf5xx_pcm_hw_free,
index c782e311fd56a38d9c0ad04ccf11e82bd851c4f7..5e5aafb6485f0bce67bf211a24bc475db69f686b 100644 (file)
@@ -128,7 +128,6 @@ static void enqueue_cmd(struct snd_ac97 *ac97, __u16 addr, __u16 data)
        int nextfrag = sport_tx_curr_frag(sport);
        struct ac97_frame *nextwrite;
 
-       sport_incfrag(sport, &nextfrag, 1);
        sport_incfrag(sport, &nextfrag, 1);
 
        nextwrite = (struct ac97_frame *)(sport->tx_buf + \
diff --git a/sound/soc/blackfin/bf5xx-ad73311.c b/sound/soc/blackfin/bf5xx-ad73311.c
new file mode 100644 (file)
index 0000000..622c9b9
--- /dev/null
@@ -0,0 +1,240 @@
+/*
+ * File:         sound/soc/blackfin/bf5xx-ad73311.c
+ * Author:       Cliff Cai <Cliff.Cai@analog.com>
+ *
+ * Created:      Thur Sep 25 2008
+ * Description:  Board driver for ad73311 sound chip
+ *
+ * Modified:
+ *               Copyright 2008 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm_params.h>
+
+#include <asm/blackfin.h>
+#include <asm/cacheflush.h>
+#include <asm/irq.h>
+#include <asm/dma.h>
+#include <asm/portmux.h>
+
+#include "../codecs/ad73311.h"
+#include "bf5xx-sport.h"
+#include "bf5xx-i2s-pcm.h"
+#include "bf5xx-i2s.h"
+
+#if CONFIG_SND_BF5XX_SPORT_NUM == 0
+#define bfin_write_SPORT_TCR1  bfin_write_SPORT0_TCR1
+#define bfin_read_SPORT_TCR1   bfin_read_SPORT0_TCR1
+#define bfin_write_SPORT_TCR2  bfin_write_SPORT0_TCR2
+#define bfin_write_SPORT_TX16  bfin_write_SPORT0_TX16
+#define bfin_read_SPORT_STAT   bfin_read_SPORT0_STAT
+#else
+#define bfin_write_SPORT_TCR1  bfin_write_SPORT1_TCR1
+#define bfin_read_SPORT_TCR1   bfin_read_SPORT1_TCR1
+#define bfin_write_SPORT_TCR2  bfin_write_SPORT1_TCR2
+#define bfin_write_SPORT_TX16  bfin_write_SPORT1_TX16
+#define bfin_read_SPORT_STAT   bfin_read_SPORT1_STAT
+#endif
+
+#define GPIO_SE CONFIG_SND_BFIN_AD73311_SE
+
+static struct snd_soc_machine bf5xx_ad73311;
+
+static int snd_ad73311_startup(void)
+{
+       pr_debug("%s enter\n", __func__);
+
+       /* Pull up SE pin on AD73311L */
+       gpio_set_value(GPIO_SE, 1);
+       return 0;
+}
+
+static int snd_ad73311_configure(void)
+{
+       unsigned short ctrl_regs[6];
+       unsigned short status = 0;
+       int count = 0;
+
+       /* DMCLK = MCLK = 16.384 MHz
+        * SCLK = DMCLK/8 = 2.048 MHz
+        * Sample Rate = DMCLK/2048  = 8 KHz
+        */
+       ctrl_regs[0] = AD_CONTROL | AD_WRITE | CTRL_REG_B | REGB_MCDIV(0) | \
+                       REGB_SCDIV(0) | REGB_DIRATE(0);
+       ctrl_regs[1] = AD_CONTROL | AD_WRITE | CTRL_REG_C | REGC_PUDEV | \
+                       REGC_PUADC | REGC_PUDAC | REGC_PUREF | REGC_REFUSE ;
+       ctrl_regs[2] = AD_CONTROL | AD_WRITE | CTRL_REG_D | REGD_OGS(2) | \
+                       REGD_IGS(2);
+       ctrl_regs[3] = AD_CONTROL | AD_WRITE | CTRL_REG_E | REGE_DA(0x1f);
+       ctrl_regs[4] = AD_CONTROL | AD_WRITE | CTRL_REG_F | REGF_SEEN ;
+       ctrl_regs[5] = AD_CONTROL | AD_WRITE | CTRL_REG_A | REGA_MODE_DATA;
+
+       local_irq_disable();
+       snd_ad73311_startup();
+       udelay(1);
+
+       bfin_write_SPORT_TCR1(TFSR);
+       bfin_write_SPORT_TCR2(0xF);
+       SSYNC();
+
+       /* SPORT Tx Register is a 8 x 16 FIFO, all the data can be put to
+        * FIFO before enable SPORT to transfer the data
+        */
+       for (count = 0; count < 6; count++)
+               bfin_write_SPORT_TX16(ctrl_regs[count]);
+       SSYNC();
+       bfin_write_SPORT_TCR1(bfin_read_SPORT_TCR1() | TSPEN);
+       SSYNC();
+
+       /* When TUVF is set, the data is already send out */
+       while (!(status & TUVF) && count++ < 10000) {
+               udelay(1);
+               status = bfin_read_SPORT_STAT();
+               SSYNC();
+       }
+       bfin_write_SPORT_TCR1(bfin_read_SPORT_TCR1() & ~TSPEN);
+       SSYNC();
+       local_irq_enable();
+
+       if (count == 10000) {
+               printk(KERN_ERR "ad73311: failed to configure codec\n");
+               return -1;
+       }
+       return 0;
+}
+
+static int bf5xx_probe(struct platform_device *pdev)
+{
+       int err;
+       if (gpio_request(GPIO_SE, "AD73311_SE")) {
+               printk(KERN_ERR "%s: Failed ro request GPIO_%d\n", __func__, GPIO_SE);
+               return -EBUSY;
+       }
+
+       gpio_direction_output(GPIO_SE, 0);
+
+       err = snd_ad73311_configure();
+       if (err < 0)
+               return -EFAULT;
+
+       return 0;
+}
+
+static int bf5xx_ad73311_startup(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+
+       pr_debug("%s enter\n", __func__);
+       cpu_dai->private_data = sport_handle;
+       return 0;
+}
+
+static int bf5xx_ad73311_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       int ret = 0;
+
+       pr_debug("%s rate %d format %x\n", __func__, params_rate(params),
+               params_format(params));
+
+       /* set cpu DAI configuration */
+       ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_A |
+               SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+
+static struct snd_soc_ops bf5xx_ad73311_ops = {
+       .startup = bf5xx_ad73311_startup,
+       .hw_params = bf5xx_ad73311_hw_params,
+};
+
+static struct snd_soc_dai_link bf5xx_ad73311_dai = {
+       .name = "ad73311",
+       .stream_name = "AD73311",
+       .cpu_dai = &bf5xx_i2s_dai,
+       .codec_dai = &ad73311_dai,
+       .ops = &bf5xx_ad73311_ops,
+};
+
+static struct snd_soc_machine bf5xx_ad73311 = {
+       .name = "bf5xx_ad73311",
+       .probe = bf5xx_probe,
+       .dai_link = &bf5xx_ad73311_dai,
+       .num_links = 1,
+};
+
+static struct snd_soc_device bf5xx_ad73311_snd_devdata = {
+       .machine = &bf5xx_ad73311,
+       .platform = &bf5xx_i2s_soc_platform,
+       .codec_dev = &soc_codec_dev_ad73311,
+};
+
+static struct platform_device *bf52x_ad73311_snd_device;
+
+static int __init bf5xx_ad73311_init(void)
+{
+       int ret;
+
+       pr_debug("%s enter\n", __func__);
+       bf52x_ad73311_snd_device = platform_device_alloc("soc-audio", -1);
+       if (!bf52x_ad73311_snd_device)
+               return -ENOMEM;
+
+       platform_set_drvdata(bf52x_ad73311_snd_device, &bf5xx_ad73311_snd_devdata);
+       bf5xx_ad73311_snd_devdata.dev = &bf52x_ad73311_snd_device->dev;
+       ret = platform_device_add(bf52x_ad73311_snd_device);
+
+       if (ret)
+               platform_device_put(bf52x_ad73311_snd_device);
+
+       return ret;
+}
+
+static void __exit bf5xx_ad73311_exit(void)
+{
+       pr_debug("%s enter\n", __func__);
+       platform_device_unregister(bf52x_ad73311_snd_device);
+}
+
+module_init(bf5xx_ad73311_init);
+module_exit(bf5xx_ad73311_exit);
+
+/* Module information */
+MODULE_AUTHOR("Cliff Cai");
+MODULE_DESCRIPTION("ALSA SoC AD73311 Blackfin");
+MODULE_LICENSE("GPL");
+
index 43a4092eeb89f0d623df6b5fa0dda8b6a24d6bb8..827587f08180de31774c0fdc79817189d2bf605b 100644 (file)
@@ -70,6 +70,13 @@ static struct sport_param sport_params[2] = {
        }
 };
 
+static u16 sport_req[][7] = {
+               { P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS,
+                 P_SPORT0_DRPRI, P_SPORT0_RSCLK, 0},
+               { P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS,
+                 P_SPORT1_DRPRI, P_SPORT1_RSCLK, 0},
+};
+
 static int bf5xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
                unsigned int fmt)
 {
@@ -78,6 +85,14 @@ static int bf5xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
        /* interface format:support I2S,slave mode */
        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
        case SND_SOC_DAIFMT_I2S:
+               bf5xx_i2s.tcr1 |= TFSR | TCKFE;
+               bf5xx_i2s.rcr1 |= RFSR | RCKFE;
+               bf5xx_i2s.tcr2 |= TSFSE;
+               bf5xx_i2s.rcr2 |= RSFSE;
+               break;
+       case SND_SOC_DAIFMT_DSP_A:
+               bf5xx_i2s.tcr1 |= TFSR;
+               bf5xx_i2s.rcr1 |= RFSR;
                break;
        case SND_SOC_DAIFMT_LEFT_J:
                ret = -EINVAL;
@@ -127,14 +142,17 @@ static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream,
        case SNDRV_PCM_FORMAT_S16_LE:
                bf5xx_i2s.tcr2 |= 15;
                bf5xx_i2s.rcr2 |= 15;
+               sport_handle->wdsize = 2;
                break;
        case SNDRV_PCM_FORMAT_S24_LE:
                bf5xx_i2s.tcr2 |= 23;
                bf5xx_i2s.rcr2 |= 23;
+               sport_handle->wdsize = 3;
                break;
        case SNDRV_PCM_FORMAT_S32_LE:
                bf5xx_i2s.tcr2 |= 31;
                bf5xx_i2s.rcr2 |= 31;
+               sport_handle->wdsize = 4;
                break;
        }
 
@@ -145,17 +163,17 @@ static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream,
                 * need to configure both of them at the time when the first
                 * stream is opened.
                 *
-                * CPU DAI format:I2S, slave mode.
+                * CPU DAI:slave mode.
                 */
-               ret = sport_config_rx(sport_handle, RFSR | RCKFE,
-                                     RSFSE|bf5xx_i2s.rcr2, 0, 0);
+               ret = sport_config_rx(sport_handle, bf5xx_i2s.rcr1,
+                                     bf5xx_i2s.rcr2, 0, 0);
                if (ret) {
                        pr_err("SPORT is busy!\n");
                        return -EBUSY;
                }
 
-               ret = sport_config_tx(sport_handle, TFSR | TCKFE,
-                                     TSFSE|bf5xx_i2s.tcr2, 0, 0);
+               ret = sport_config_tx(sport_handle, bf5xx_i2s.tcr1,
+                                     bf5xx_i2s.tcr2, 0, 0);
                if (ret) {
                        pr_err("SPORT is busy!\n");
                        return -EBUSY;
@@ -174,13 +192,6 @@ static void bf5xx_i2s_shutdown(struct snd_pcm_substream *substream)
 static int bf5xx_i2s_probe(struct platform_device *pdev,
                           struct snd_soc_dai *dai)
 {
-       u16 sport_req[][7] = {
-               { P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS,
-                 P_SPORT0_DRPRI, P_SPORT0_RSCLK, 0},
-               { P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS,
-                 P_SPORT1_DRPRI, P_SPORT1_RSCLK, 0},
-       };
-
        pr_debug("%s enter\n", __func__);
        if (peripheral_request_list(&sport_req[sport_num][0], "soc-audio")) {
                pr_err("Requesting Peripherals failed\n");
@@ -198,6 +209,13 @@ static int bf5xx_i2s_probe(struct platform_device *pdev,
        return 0;
 }
 
+static void bf5xx_i2s_remove(struct platform_device *pdev,
+                          struct snd_soc_dai *dai)
+{
+       pr_debug("%s enter\n", __func__);
+       peripheral_free_list(&sport_req[sport_num][0]);
+}
+
 #ifdef CONFIG_PM
 static int bf5xx_i2s_suspend(struct platform_device *dev,
                             struct snd_soc_dai *dai)
@@ -263,15 +281,16 @@ struct snd_soc_dai bf5xx_i2s_dai = {
        .id = 0,
        .type = SND_SOC_DAI_I2S,
        .probe = bf5xx_i2s_probe,
+       .remove = bf5xx_i2s_remove,
        .suspend = bf5xx_i2s_suspend,
        .resume = bf5xx_i2s_resume,
        .playback = {
-               .channels_min = 2,
+               .channels_min = 1,
                .channels_max = 2,
                .rates = BF5XX_I2S_RATES,
                .formats = BF5XX_I2S_FORMATS,},
        .capture = {
-               .channels_min = 2,
+               .channels_min = 1,
                .channels_max = 2,
                .rates = BF5XX_I2S_RATES,
                .formats = BF5XX_I2S_FORMATS,},
index 4c163454bbf8410570e2f8e43cf06da224cae66e..fcadcc081f7fe4994a2dc3dbc0514656c7c6cd06 100644 (file)
@@ -123,6 +123,8 @@ struct sport_device {
        int rx_pos;
        unsigned int tx_buffer_size;
        unsigned int rx_buffer_size;
+       int tx_delay_pos;
+       int once;
 #endif
        void *private_data;
 };
index e0b9869df0f107ed2876a2a8b9c8893ff8740cd5..4975d8573e4f51414cf2a24c03943c56fd1eeb51 100644 (file)
@@ -3,9 +3,11 @@ config SND_SOC_ALL_CODECS
        depends on I2C
        select SPI
        select SPI_MASTER
+       select SND_SOC_AD73311
        select SND_SOC_AK4535
        select SND_SOC_CS4270
        select SND_SOC_SSM2602
+       select SND_SOC_TLV320AIC23
        select SND_SOC_TLV320AIC26
        select SND_SOC_TLV320AIC3X
        select SND_SOC_UDA1380
@@ -34,6 +36,9 @@ config SND_SOC_AC97_CODEC
 config SND_SOC_AD1980
        tristate
 
+config SND_SOC_AD73311
+       tristate
+
 config SND_SOC_AK4535
        tristate
 
@@ -58,9 +63,13 @@ config SND_SOC_CS4270_VD33_ERRATA
 config SND_SOC_SSM2602
        tristate
 
+config SND_SOC_TLV320AIC23
+       tristate
+       depends on I2C
+
 config SND_SOC_TLV320AIC26
        tristate "TI TLV320AIC26 Codec support"
-       depends on SND_SOC && SPI
+       depends on SPI
 
 config SND_SOC_TLV320AIC3X
        tristate
index f977978a3409e2c19584f1819ddde1989bd9aeef..90f0a585fc70e1f5a4d9a9be1b8514a22100917a 100644 (file)
@@ -1,8 +1,10 @@
 snd-soc-ac97-objs := ac97.o
 snd-soc-ad1980-objs := ad1980.o
+snd-soc-ad73311-objs := ad73311.o
 snd-soc-ak4535-objs := ak4535.o
 snd-soc-cs4270-objs := cs4270.o
 snd-soc-ssm2602-objs := ssm2602.o
+snd-soc-tlv320aic23-objs := tlv320aic23.o
 snd-soc-tlv320aic26-objs := tlv320aic26.o
 snd-soc-tlv320aic3x-objs := tlv320aic3x.o
 snd-soc-uda1380-objs := uda1380.o
@@ -20,9 +22,11 @@ snd-soc-wm9713-objs := wm9713.o
 
 obj-$(CONFIG_SND_SOC_AC97_CODEC)       += snd-soc-ac97.o
 obj-$(CONFIG_SND_SOC_AD1980)   += snd-soc-ad1980.o
+obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o
 obj-$(CONFIG_SND_SOC_AK4535)   += snd-soc-ak4535.o
 obj-$(CONFIG_SND_SOC_CS4270)   += snd-soc-cs4270.o
 obj-$(CONFIG_SND_SOC_SSM2602)  += snd-soc-ssm2602.o
+obj-$(CONFIG_SND_SOC_TLV320AIC23)      += snd-soc-tlv320aic23.o
 obj-$(CONFIG_SND_SOC_TLV320AIC26)      += snd-soc-tlv320aic26.o
 obj-$(CONFIG_SND_SOC_TLV320AIC3X)      += snd-soc-tlv320aic3x.o
 obj-$(CONFIG_SND_SOC_UDA1380)  += snd-soc-uda1380.o
index 61fd96ca7bc782588e17655ebd8dd12887837e75..bd1ebdc6c86ce0e6ef021139f5ac10b93831f4d4 100644 (file)
@@ -2,8 +2,7 @@
  * ac97.c  --  ALSA Soc AC97 codec support
  *
  * Copyright 2005 Wolfson Microelectronics PLC.
- * Author: Liam Girdwood
- *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
  *
  *  This program is free software; you can redistribute  it and/or modify it
  *  under  the terms of  the GNU General  Public License as published by the
index 4e09c1f2c063a3f335188d043314ff0dd525f8ac..1397b8e06c0b41eda7002815a276baba8f3ea035 100644 (file)
@@ -13,7 +13,6 @@
 
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/device.h>
 #include <sound/core.h>
diff --git a/sound/soc/codecs/ad73311.c b/sound/soc/codecs/ad73311.c
new file mode 100644 (file)
index 0000000..37af860
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * ad73311.c  --  ALSA Soc AD73311 codec support
+ *
+ * Copyright:  Analog Device Inc.
+ * Author:     Cliff Cai <cliff.cai@analog.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.
+ *
+ *  Revision history
+ *    25th Sep 2008   Initial version.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/ac97_codec.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#include "ad73311.h"
+
+struct snd_soc_dai ad73311_dai = {
+       .name = "AD73311",
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 1,
+               .channels_max = 1,
+               .rates = SNDRV_PCM_RATE_8000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE, },
+       .capture = {
+               .stream_name = "Capture",
+               .channels_min = 1,
+               .channels_max = 1,
+               .rates = SNDRV_PCM_RATE_8000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE, },
+};
+EXPORT_SYMBOL_GPL(ad73311_dai);
+
+static int ad73311_soc_probe(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec;
+       int ret = 0;
+
+       codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+       if (codec == NULL)
+               return -ENOMEM;
+       mutex_init(&codec->mutex);
+       codec->name = "AD73311";
+       codec->owner = THIS_MODULE;
+       codec->dai = &ad73311_dai;
+       codec->num_dai = 1;
+       socdev->codec = codec;
+       INIT_LIST_HEAD(&codec->dapm_widgets);
+       INIT_LIST_HEAD(&codec->dapm_paths);
+
+       /* register pcms */
+       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+       if (ret < 0) {
+               printk(KERN_ERR "ad73311: failed to create pcms\n");
+               goto pcm_err;
+       }
+
+       ret = snd_soc_register_card(socdev);
+       if (ret < 0) {
+               printk(KERN_ERR "ad73311: failed to register card\n");
+               goto register_err;
+       }
+
+       return ret;
+
+register_err:
+       snd_soc_free_pcms(socdev);
+pcm_err:
+       kfree(socdev->codec);
+       socdev->codec = NULL;
+       return ret;
+}
+
+static int ad73311_soc_remove(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec = socdev->codec;
+
+       if (codec == NULL)
+               return 0;
+       snd_soc_free_pcms(socdev);
+       kfree(codec);
+       return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_ad73311 = {
+       .probe =        ad73311_soc_probe,
+       .remove =       ad73311_soc_remove,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_ad73311);
+
+MODULE_DESCRIPTION("ASoC ad73311 driver");
+MODULE_AUTHOR("Cliff Cai ");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/ad73311.h b/sound/soc/codecs/ad73311.h
new file mode 100644 (file)
index 0000000..507ce0c
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * File:         sound/soc/codec/ad73311.h
+ * Based on:
+ * Author:       Cliff Cai <cliff.cai@analog.com>
+ *
+ * Created:      Thur Sep 25, 2008
+ * Description:  definitions for AD73311 registers
+ *
+ *
+ * Modified:
+ *               Copyright 2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef __AD73311_H__
+#define __AD73311_H__
+
+#define AD_CONTROL     0x8000
+#define AD_DATA                0x0000
+#define AD_READ                0x4000
+#define AD_WRITE       0x0000
+
+/* Control register A */
+#define CTRL_REG_A     (0 << 8)
+
+#define REGA_MODE_PRO  0x00
+#define REGA_MODE_DATA 0x01
+#define REGA_MODE_MIXED        0x03
+#define REGA_DLB               0x04
+#define REGA_SLB               0x08
+#define REGA_DEVC(x)           ((x & 0x7) << 4)
+#define REGA_RESET             0x80
+
+/* Control register B */
+#define CTRL_REG_B     (1 << 8)
+
+#define REGB_DIRATE(x) (x & 0x3)
+#define REGB_SCDIV(x)  ((x & 0x3) << 2)
+#define REGB_MCDIV(x)  ((x & 0x7) << 4)
+#define REGB_CEE               (1 << 7)
+
+/* Control register C */
+#define CTRL_REG_C     (2 << 8)
+
+#define REGC_PUDEV             (1 << 0)
+#define REGC_PUADC             (1 << 3)
+#define REGC_PUDAC             (1 << 4)
+#define REGC_PUREF             (1 << 5)
+#define REGC_REFUSE            (1 << 6)
+
+/* Control register D */
+#define CTRL_REG_D     (3 << 8)
+
+#define REGD_IGS(x)            (x & 0x7)
+#define REGD_RMOD              (1 << 3)
+#define REGD_OGS(x)            ((x & 0x7) << 4)
+#define REGD_MUTE              (x << 7)
+
+/* Control register E */
+#define CTRL_REG_E     (4 << 8)
+
+#define REGE_DA(x)             (x & 0x1f)
+#define REGE_IBYP              (1 << 5)
+
+/* Control register F */
+#define CTRL_REG_F     (5 << 8)
+
+#define REGF_SEEN              (1 << 5)
+#define REGF_INV               (1 << 6)
+#define REGF_ALB               (1 << 7)
+
+extern struct snd_soc_dai ad73311_dai;
+extern struct snd_soc_codec_device soc_codec_dev_ad73311;
+#endif
index 088cf99277203ff4d729d722629ed8cf222f2cb0..2a89b5888e11c33bdedf44b817e0c61282b95d0d 100644 (file)
@@ -28,7 +28,6 @@
 
 #include "ak4535.h"
 
-#define AUDIO_NAME "ak4535"
 #define AK4535_VERSION "0.3"
 
 struct snd_soc_codec_device soc_codec_dev_ak4535;
index 940ce1c3522e007733c9bfc9066d822f21727077..44ef0dacd564701b3999316d9c2e21c5b41ec4a8 100644 (file)
@@ -42,7 +42,6 @@
 
 #include "ssm2602.h"
 
-#define AUDIO_NAME "ssm2602"
 #define SSM2602_VERSION "0.1"
 
 struct snd_soc_codec_device soc_codec_dev_ssm2602;
diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c
new file mode 100644 (file)
index 0000000..bac7815
--- /dev/null
@@ -0,0 +1,714 @@
+/*
+ * ALSA SoC TLV320AIC23 codec driver
+ *
+ * Author:      Arun KS, <arunks@mistralsolutions.com>
+ * Copyright:   (C) 2008 Mistral Solutions Pvt Ltd.,
+ *
+ * Based on sound/soc/codecs/wm8731.c by 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
+ * published by the Free Software Foundation.
+ *
+ * Notes:
+ *  The AIC23 is a driver for a low power stereo audio
+ *  codec tlv320aic23
+ *
+ *  The machine layer should disable unsupported inputs/outputs by
+ *  snd_soc_dapm_disable_pin(codec, "LHPOUT"), etc.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+#include <sound/initval.h>
+
+#include "tlv320aic23.h"
+
+#define AIC23_VERSION "0.1"
+
+struct tlv320aic23_srate_reg_info {
+       u32 sample_rate;
+       u8 control;             /* SR3, SR2, SR1, SR0 and BOSR */
+       u8 divider;             /* if 0 CLKIN = MCLK, if 1 CLKIN = MCLK/2 */
+};
+
+/*
+ * AIC23 register cache
+ */
+static const u16 tlv320aic23_reg[] = {
+       0x0097, 0x0097, 0x00F9, 0x00F9, /* 0 */
+       0x001A, 0x0004, 0x0007, 0x0001, /* 4 */
+       0x0020, 0x0000, 0x0000, 0x0000, /* 8 */
+       0x0000, 0x0000, 0x0000, 0x0000, /* 12 */
+};
+
+/*
+ * read tlv320aic23 register cache
+ */
+static inline unsigned int tlv320aic23_read_reg_cache(struct snd_soc_codec
+                                                     *codec, unsigned int reg)
+{
+       u16 *cache = codec->reg_cache;
+       if (reg >= ARRAY_SIZE(tlv320aic23_reg))
+               return -1;
+       return cache[reg];
+}
+
+/*
+ * write tlv320aic23 register cache
+ */
+static inline void tlv320aic23_write_reg_cache(struct snd_soc_codec *codec,
+                                              u8 reg, u16 value)
+{
+       u16 *cache = codec->reg_cache;
+       if (reg >= ARRAY_SIZE(tlv320aic23_reg))
+               return;
+       cache[reg] = value;
+}
+
+/*
+ * write to the tlv320aic23 register space
+ */
+static int tlv320aic23_write(struct snd_soc_codec *codec, unsigned int reg,
+                            unsigned int value)
+{
+
+       u8 data;
+
+       /* TLV320AIC23 has 7 bit address and 9 bits of data
+        * so we need to switch one data bit into reg and rest
+        * of data into val
+        */
+
+       if ((reg < 0 || reg > 9) && (reg != 15)) {
+               printk(KERN_WARNING "%s Invalid register R%d\n", __func__, reg);
+               return -1;
+       }
+
+       data = (reg << 1) | (value >> 8 & 0x01);
+
+       tlv320aic23_write_reg_cache(codec, reg, value);
+
+       if (codec->hw_write(codec->control_data, data,
+                           (value & 0xff)) == 0)
+               return 0;
+
+       printk(KERN_ERR "%s cannot write %03x to register R%d\n", __func__,
+              value, reg);
+
+       return -EIO;
+}
+
+static const char *rec_src_text[] = { "Line", "Mic" };
+static const char *deemph_text[] = {"None", "32Khz", "44.1Khz", "48Khz"};
+
+static const struct soc_enum rec_src_enum =
+       SOC_ENUM_SINGLE(TLV320AIC23_ANLG, 2, 2, rec_src_text);
+
+static const struct snd_kcontrol_new tlv320aic23_rec_src_mux_controls =
+SOC_DAPM_ENUM("Input Select", rec_src_enum);
+
+static const struct soc_enum tlv320aic23_rec_src =
+       SOC_ENUM_SINGLE(TLV320AIC23_ANLG, 2, 2, rec_src_text);
+static const struct soc_enum tlv320aic23_deemph =
+       SOC_ENUM_SINGLE(TLV320AIC23_DIGT, 1, 4, deemph_text);
+
+static const DECLARE_TLV_DB_SCALE(out_gain_tlv, -12100, 100, 0);
+static const DECLARE_TLV_DB_SCALE(input_gain_tlv, -1725, 75, 0);
+static const DECLARE_TLV_DB_SCALE(sidetone_vol_tlv, -1800, 300, 0);
+
+static int snd_soc_tlv320aic23_put_volsw(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       u16 val, reg;
+
+       val = (ucontrol->value.integer.value[0] & 0x07);
+
+       /* linear conversion to userspace
+       * 000   =       -6db
+       * 001   =       -9db
+       * 010   =       -12db
+       * 011   =       -18db (Min)
+       * 100   =       0db (Max)
+       */
+       val = (val >= 4) ? 4  : (3 - val);
+
+       reg = tlv320aic23_read_reg_cache(codec, TLV320AIC23_ANLG) & (~0x1C0);
+       tlv320aic23_write(codec, TLV320AIC23_ANLG, reg | (val << 6));
+
+       return 0;
+}
+
+static int snd_soc_tlv320aic23_get_volsw(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       u16 val;
+
+       val = tlv320aic23_read_reg_cache(codec, TLV320AIC23_ANLG) & (0x1C0);
+       val = val >> 6;
+       val = (val >= 4) ? 4  : (3 -  val);
+       ucontrol->value.integer.value[0] = val;
+       return 0;
+
+}
+
+#define SOC_TLV320AIC23_SINGLE_TLV(xname, reg, shift, max, invert, tlv_array) \
+{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+       .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
+                SNDRV_CTL_ELEM_ACCESS_READWRITE,\
+       .tlv.p = (tlv_array), \
+       .info = snd_soc_info_volsw, .get = snd_soc_tlv320aic23_get_volsw,\
+       .put = snd_soc_tlv320aic23_put_volsw, \
+       .private_value =  SOC_SINGLE_VALUE(reg, shift, max, invert) }
+
+static const struct snd_kcontrol_new tlv320aic23_snd_controls[] = {
+       SOC_DOUBLE_R_TLV("Digital Playback Volume", TLV320AIC23_LCHNVOL,
+                        TLV320AIC23_RCHNVOL, 0, 127, 0, out_gain_tlv),
+       SOC_SINGLE("Digital Playback Switch", TLV320AIC23_DIGT, 3, 1, 1),
+       SOC_DOUBLE_R("Line Input Switch", TLV320AIC23_LINVOL,
+                    TLV320AIC23_RINVOL, 7, 1, 0),
+       SOC_DOUBLE_R_TLV("Line Input Volume", TLV320AIC23_LINVOL,
+                        TLV320AIC23_RINVOL, 0, 31, 0, input_gain_tlv),
+       SOC_SINGLE("Mic Input Switch", TLV320AIC23_ANLG, 1, 1, 1),
+       SOC_SINGLE("Mic Booster Switch", TLV320AIC23_ANLG, 0, 1, 0),
+       SOC_TLV320AIC23_SINGLE_TLV("Sidetone Volume", TLV320AIC23_ANLG,
+                                 6, 4, 0, sidetone_vol_tlv),
+       SOC_ENUM("Playback De-emphasis", tlv320aic23_deemph),
+};
+
+/* add non dapm controls */
+static int tlv320aic23_add_controls(struct snd_soc_codec *codec)
+{
+
+       int err, i;
+
+       for (i = 0; i < ARRAY_SIZE(tlv320aic23_snd_controls); i++) {
+               err = snd_ctl_add(codec->card,
+                                 snd_soc_cnew(&tlv320aic23_snd_controls[i],
+                                              codec, NULL));
+               if (err < 0)
+                       return err;
+       }
+
+       return 0;
+
+}
+
+/* PGA Mixer controls for Line and Mic switch */
+static const struct snd_kcontrol_new tlv320aic23_output_mixer_controls[] = {
+       SOC_DAPM_SINGLE("Line Bypass Switch", TLV320AIC23_ANLG, 3, 1, 0),
+       SOC_DAPM_SINGLE("Mic Sidetone Switch", TLV320AIC23_ANLG, 5, 1, 0),
+       SOC_DAPM_SINGLE("Playback Switch", TLV320AIC23_ANLG, 4, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget tlv320aic23_dapm_widgets[] = {
+       SND_SOC_DAPM_DAC("DAC", "Playback", TLV320AIC23_PWR, 3, 1),
+       SND_SOC_DAPM_ADC("ADC", "Capture", TLV320AIC23_PWR, 2, 1),
+       SND_SOC_DAPM_MUX("Capture Source", SND_SOC_NOPM, 0, 0,
+                        &tlv320aic23_rec_src_mux_controls),
+       SND_SOC_DAPM_MIXER("Output Mixer", TLV320AIC23_PWR, 4, 1,
+                          &tlv320aic23_output_mixer_controls[0],
+                          ARRAY_SIZE(tlv320aic23_output_mixer_controls)),
+       SND_SOC_DAPM_PGA("Line Input", TLV320AIC23_PWR, 0, 1, NULL, 0),
+       SND_SOC_DAPM_PGA("Mic Input", TLV320AIC23_PWR, 1, 1, NULL, 0),
+
+       SND_SOC_DAPM_OUTPUT("LHPOUT"),
+       SND_SOC_DAPM_OUTPUT("RHPOUT"),
+       SND_SOC_DAPM_OUTPUT("LOUT"),
+       SND_SOC_DAPM_OUTPUT("ROUT"),
+
+       SND_SOC_DAPM_INPUT("LLINEIN"),
+       SND_SOC_DAPM_INPUT("RLINEIN"),
+
+       SND_SOC_DAPM_INPUT("MICIN"),
+};
+
+static const struct snd_soc_dapm_route intercon[] = {
+       /* Output Mixer */
+       {"Output Mixer", "Line Bypass Switch", "Line Input"},
+       {"Output Mixer", "Playback Switch", "DAC"},
+       {"Output Mixer", "Mic Sidetone Switch", "Mic Input"},
+
+       /* Outputs */
+       {"RHPOUT", NULL, "Output Mixer"},
+       {"LHPOUT", NULL, "Output Mixer"},
+       {"LOUT", NULL, "Output Mixer"},
+       {"ROUT", NULL, "Output Mixer"},
+
+       /* Inputs */
+       {"Line Input", "NULL", "LLINEIN"},
+       {"Line Input", "NULL", "RLINEIN"},
+
+       {"Mic Input", "NULL", "MICIN"},
+
+       /* input mux */
+       {"Capture Source", "Line", "Line Input"},
+       {"Capture Source", "Mic", "Mic Input"},
+       {"ADC", NULL, "Capture Source"},
+
+};
+
+/* tlv320aic23 related */
+static const struct tlv320aic23_srate_reg_info srate_reg_info[] = {
+       {4000, 0x06, 1},        /*  4000 */
+       {8000, 0x06, 0},        /*  8000 */
+       {16000, 0x0C, 1},       /* 16000 */
+       {22050, 0x11, 1},       /* 22050 */
+       {24000, 0x00, 1},       /* 24000 */
+       {32000, 0x0C, 0},       /* 32000 */
+       {44100, 0x11, 0},       /* 44100 */
+       {48000, 0x00, 0},       /* 48000 */
+       {88200, 0x1F, 0},       /* 88200 */
+       {96000, 0x0E, 0},       /* 96000 */
+};
+
+static int tlv320aic23_add_widgets(struct snd_soc_codec *codec)
+{
+       snd_soc_dapm_new_controls(codec, tlv320aic23_dapm_widgets,
+                                 ARRAY_SIZE(tlv320aic23_dapm_widgets));
+
+       /* set up audio path interconnects */
+       snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
+
+       snd_soc_dapm_new_widgets(codec);
+       return 0;
+}
+
+static int tlv320aic23_hw_params(struct snd_pcm_substream *substream,
+                                struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_device *socdev = rtd->socdev;
+       struct snd_soc_codec *codec = socdev->codec;
+       u16 iface_reg, data;
+       u8 count = 0;
+
+       iface_reg =
+           tlv320aic23_read_reg_cache(codec,
+                                      TLV320AIC23_DIGT_FMT) & ~(0x03 << 2);
+
+       /* Search for the right sample rate */
+       /* Verify what happens if the rate is not supported
+        * now it goes to 96Khz */
+       while ((srate_reg_info[count].sample_rate != params_rate(params)) &&
+              (count < ARRAY_SIZE(srate_reg_info))) {
+               count++;
+       }
+
+       data =  (srate_reg_info[count].divider << TLV320AIC23_CLKIN_SHIFT) |
+               (srate_reg_info[count]. control << TLV320AIC23_BOSR_SHIFT) |
+               TLV320AIC23_USB_CLK_ON;
+
+       tlv320aic23_write(codec, TLV320AIC23_SRATE, data);
+
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               break;
+       case SNDRV_PCM_FORMAT_S20_3LE:
+               iface_reg |= (0x01 << 2);
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               iface_reg |= (0x02 << 2);
+               break;
+       case SNDRV_PCM_FORMAT_S32_LE:
+               iface_reg |= (0x03 << 2);
+               break;
+       }
+       tlv320aic23_write(codec, TLV320AIC23_DIGT_FMT, iface_reg);
+
+       return 0;
+}
+
+static int tlv320aic23_pcm_prepare(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_device *socdev = rtd->socdev;
+       struct snd_soc_codec *codec = socdev->codec;
+
+       /* set active */
+       tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x0001);
+
+       return 0;
+}
+
+static void tlv320aic23_shutdown(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_device *socdev = rtd->socdev;
+       struct snd_soc_codec *codec = socdev->codec;
+
+       /* deactivate */
+       if (!codec->active) {
+               udelay(50);
+               tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x0);
+       }
+}
+
+static int tlv320aic23_mute(struct snd_soc_dai *dai, int mute)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       u16 reg;
+
+       reg = tlv320aic23_read_reg_cache(codec, TLV320AIC23_DIGT);
+       if (mute)
+               reg |= TLV320AIC23_DACM_MUTE;
+
+       else
+               reg &= ~TLV320AIC23_DACM_MUTE;
+
+       tlv320aic23_write(codec, TLV320AIC23_DIGT, reg);
+
+       return 0;
+}
+
+static int tlv320aic23_set_dai_fmt(struct snd_soc_dai *codec_dai,
+                                  unsigned int fmt)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       u16 iface_reg;
+
+       iface_reg =
+           tlv320aic23_read_reg_cache(codec, TLV320AIC23_DIGT_FMT) & (~0x03);
+
+       /* set master/slave audio interface */
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               iface_reg |= TLV320AIC23_MS_MASTER;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               break;
+       default:
+               return -EINVAL;
+
+       }
+
+       /* interface format */
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               iface_reg |= TLV320AIC23_FOR_I2S;
+               break;
+       case SND_SOC_DAIFMT_DSP_A:
+               iface_reg |= TLV320AIC23_FOR_DSP;
+               break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               iface_reg |= TLV320AIC23_FOR_LJUST;
+               break;
+       default:
+               return -EINVAL;
+
+       }
+
+       tlv320aic23_write(codec, TLV320AIC23_DIGT_FMT, iface_reg);
+
+       return 0;
+}
+
+static int tlv320aic23_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+                                     int clk_id, unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+
+       switch (freq) {
+       case 12000000:
+               return 0;
+       }
+       return -EINVAL;
+}
+
+static int tlv320aic23_set_bias_level(struct snd_soc_codec *codec,
+                                     enum snd_soc_bias_level level)
+{
+       u16 reg = tlv320aic23_read_reg_cache(codec, TLV320AIC23_PWR) & 0xff7f;
+
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+               /* vref/mid, osc on, dac unmute */
+               tlv320aic23_write(codec, TLV320AIC23_PWR, reg);
+               break;
+       case SND_SOC_BIAS_PREPARE:
+               break;
+       case SND_SOC_BIAS_STANDBY:
+               /* everything off except vref/vmid, */
+               tlv320aic23_write(codec, TLV320AIC23_PWR, reg | 0x0040);
+               break;
+       case SND_SOC_BIAS_OFF:
+               /* everything off, dac mute, inactive */
+               tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x0);
+               tlv320aic23_write(codec, TLV320AIC23_PWR, 0xffff);
+               break;
+       }
+       codec->bias_level = level;
+       return 0;
+}
+
+#define AIC23_RATES    SNDRV_PCM_RATE_8000_96000
+#define AIC23_FORMATS  (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+                        SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+struct snd_soc_dai tlv320aic23_dai = {
+       .name = "tlv320aic23",
+       .playback = {
+                    .stream_name = "Playback",
+                    .channels_min = 2,
+                    .channels_max = 2,
+                    .rates = AIC23_RATES,
+                    .formats = AIC23_FORMATS,},
+       .capture = {
+                   .stream_name = "Capture",
+                   .channels_min = 2,
+                   .channels_max = 2,
+                   .rates = AIC23_RATES,
+                   .formats = AIC23_FORMATS,},
+       .ops = {
+               .prepare = tlv320aic23_pcm_prepare,
+               .hw_params = tlv320aic23_hw_params,
+               .shutdown = tlv320aic23_shutdown,
+               },
+       .dai_ops = {
+                   .digital_mute = tlv320aic23_mute,
+                   .set_fmt = tlv320aic23_set_dai_fmt,
+                   .set_sysclk = tlv320aic23_set_dai_sysclk,
+                   }
+};
+EXPORT_SYMBOL_GPL(tlv320aic23_dai);
+
+static int tlv320aic23_suspend(struct platform_device *pdev,
+                              pm_message_t state)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec = socdev->codec;
+
+       tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x0);
+       tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+       return 0;
+}
+
+static int tlv320aic23_resume(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec = socdev->codec;
+       int i;
+       u16 reg;
+
+       /* Sync reg_cache with the hardware */
+       for (reg = 0; reg < ARRAY_SIZE(tlv320aic23_reg); i++) {
+               u16 val = tlv320aic23_read_reg_cache(codec, reg);
+               tlv320aic23_write(codec, reg, val);
+       }
+
+       tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+       tlv320aic23_set_bias_level(codec, codec->suspend_bias_level);
+
+       return 0;
+}
+
+/*
+ * initialise the AIC23 driver
+ * register the mixer and dsp interfaces with the kernel
+ */
+static int tlv320aic23_init(struct snd_soc_device *socdev)
+{
+       struct snd_soc_codec *codec = socdev->codec;
+       int ret = 0;
+       u16 reg;
+
+       codec->name = "tlv320aic23";
+       codec->owner = THIS_MODULE;
+       codec->read = tlv320aic23_read_reg_cache;
+       codec->write = tlv320aic23_write;
+       codec->set_bias_level = tlv320aic23_set_bias_level;
+       codec->dai = &tlv320aic23_dai;
+       codec->num_dai = 1;
+       codec->reg_cache_size = ARRAY_SIZE(tlv320aic23_reg);
+       codec->reg_cache =
+           kmemdup(tlv320aic23_reg, sizeof(tlv320aic23_reg), GFP_KERNEL);
+       if (codec->reg_cache == NULL)
+               return -ENOMEM;
+
+       /* Reset codec */
+       tlv320aic23_write(codec, TLV320AIC23_RESET, 0);
+
+       /* register pcms */
+       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+       if (ret < 0) {
+               printk(KERN_ERR "tlv320aic23: failed to create pcms\n");
+               goto pcm_err;
+       }
+
+       /* power on device */
+       tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       tlv320aic23_write(codec, TLV320AIC23_DIGT, TLV320AIC23_DEEMP_44K);
+
+       /* Unmute input */
+       reg = tlv320aic23_read_reg_cache(codec, TLV320AIC23_LINVOL);
+       tlv320aic23_write(codec, TLV320AIC23_LINVOL,
+                         (reg & (~TLV320AIC23_LIM_MUTED)) |
+                         (TLV320AIC23_LRS_ENABLED));
+
+       reg = tlv320aic23_read_reg_cache(codec, TLV320AIC23_RINVOL);
+       tlv320aic23_write(codec, TLV320AIC23_RINVOL,
+                         (reg & (~TLV320AIC23_LIM_MUTED)) |
+                         TLV320AIC23_LRS_ENABLED);
+
+       reg = tlv320aic23_read_reg_cache(codec, TLV320AIC23_ANLG);
+       tlv320aic23_write(codec, TLV320AIC23_ANLG,
+                        (reg) & (~TLV320AIC23_BYPASS_ON) &
+                        (~TLV320AIC23_MICM_MUTED));
+
+       /* Default output volume */
+       tlv320aic23_write(codec, TLV320AIC23_LCHNVOL,
+                         TLV320AIC23_DEFAULT_OUT_VOL &
+                         TLV320AIC23_OUT_VOL_MASK);
+       tlv320aic23_write(codec, TLV320AIC23_RCHNVOL,
+                         TLV320AIC23_DEFAULT_OUT_VOL &
+                         TLV320AIC23_OUT_VOL_MASK);
+
+       tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x1);
+
+       tlv320aic23_add_controls(codec);
+       tlv320aic23_add_widgets(codec);
+       ret = snd_soc_register_card(socdev);
+       if (ret < 0) {
+               printk(KERN_ERR "tlv320aic23: failed to register card\n");
+               goto card_err;
+       }
+
+       return ret;
+
+card_err:
+       snd_soc_free_pcms(socdev);
+       snd_soc_dapm_free(socdev);
+pcm_err:
+       kfree(codec->reg_cache);
+       return ret;
+}
+static struct snd_soc_device *tlv320aic23_socdev;
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+/*
+ * If the i2c layer weren't so broken, we could pass this kind of data
+ * around
+ */
+static int tlv320aic23_codec_probe(struct i2c_client *i2c,
+                                  const struct i2c_device_id *i2c_id)
+{
+       struct snd_soc_device *socdev = tlv320aic23_socdev;
+       struct snd_soc_codec *codec = socdev->codec;
+       int ret;
+
+       if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return -EINVAL;
+
+       i2c_set_clientdata(i2c, codec);
+       codec->control_data = i2c;
+
+       ret = tlv320aic23_init(socdev);
+       if (ret < 0) {
+               printk(KERN_ERR "tlv320aic23: failed to initialise AIC23\n");
+               goto err;
+       }
+       return ret;
+
+err:
+       kfree(codec);
+       kfree(i2c);
+       return ret;
+}
+static int __exit tlv320aic23_i2c_remove(struct i2c_client *i2c)
+{
+       put_device(&i2c->dev);
+       return 0;
+}
+
+static const struct i2c_device_id tlv320aic23_id[] = {
+       {"tlv320aic23", 0},
+       {}
+};
+
+MODULE_DEVICE_TABLE(i2c, tlv320aic23_id);
+
+static struct i2c_driver tlv320aic23_i2c_driver = {
+       .driver = {
+                  .name = "tlv320aic23",
+                  },
+       .probe = tlv320aic23_codec_probe,
+       .remove = __exit_p(tlv320aic23_i2c_remove),
+       .id_table = tlv320aic23_id,
+};
+
+#endif
+
+static int tlv320aic23_probe(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec;
+       int ret = 0;
+
+       printk(KERN_INFO "AIC23 Audio Codec %s\n", AIC23_VERSION);
+
+       codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+       if (codec == NULL)
+               return -ENOMEM;
+
+       socdev->codec = codec;
+       mutex_init(&codec->mutex);
+       INIT_LIST_HEAD(&codec->dapm_widgets);
+       INIT_LIST_HEAD(&codec->dapm_paths);
+
+       tlv320aic23_socdev = socdev;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       codec->hw_write = (hw_write_t) i2c_smbus_write_byte_data;
+       codec->hw_read = NULL;
+       ret = i2c_add_driver(&tlv320aic23_i2c_driver);
+       if (ret != 0)
+               printk(KERN_ERR "can't add i2c driver");
+#endif
+       return ret;
+}
+
+static int tlv320aic23_remove(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec = socdev->codec;
+
+       if (codec->control_data)
+               tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+       snd_soc_free_pcms(socdev);
+       snd_soc_dapm_free(socdev);
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       i2c_del_driver(&tlv320aic23_i2c_driver);
+#endif
+       kfree(codec->reg_cache);
+       kfree(codec);
+
+       return 0;
+}
+struct snd_soc_codec_device soc_codec_dev_tlv320aic23 = {
+       .probe = tlv320aic23_probe,
+       .remove = tlv320aic23_remove,
+       .suspend = tlv320aic23_suspend,
+       .resume = tlv320aic23_resume,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_tlv320aic23);
+
+MODULE_DESCRIPTION("ASoC TLV320AIC23 codec driver");
+MODULE_AUTHOR("Arun KS <arunks@mistralsolutions.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/tlv320aic23.h b/sound/soc/codecs/tlv320aic23.h
new file mode 100644 (file)
index 0000000..79d1faf
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * ALSA SoC TLV320AIC23 codec driver
+ *
+ * Author:      Arun KS, <arunks@mistralsolutions.com>
+ * Copyright:   (C) 2008 Mistral Solutions Pvt Ltd
+ *
+ * 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.
+ */
+
+#ifndef _TLV320AIC23_H
+#define _TLV320AIC23_H
+
+/* Codec TLV320AIC23 */
+#define TLV320AIC23_LINVOL             0x00
+#define TLV320AIC23_RINVOL             0x01
+#define TLV320AIC23_LCHNVOL            0x02
+#define TLV320AIC23_RCHNVOL            0x03
+#define TLV320AIC23_ANLG               0x04
+#define TLV320AIC23_DIGT               0x05
+#define TLV320AIC23_PWR                        0x06
+#define TLV320AIC23_DIGT_FMT           0x07
+#define TLV320AIC23_SRATE              0x08
+#define TLV320AIC23_ACTIVE             0x09
+#define TLV320AIC23_RESET              0x0F
+
+/* Left (right) line input volume control register */
+#define TLV320AIC23_LRS_ENABLED                0x0100
+#define TLV320AIC23_LIM_MUTED          0x0080
+#define TLV320AIC23_LIV_DEFAULT                0x0017
+#define TLV320AIC23_LIV_MAX            0x001f
+#define TLV320AIC23_LIV_MIN            0x0000
+
+/* Left (right) channel headphone volume control register */
+#define TLV320AIC23_LZC_ON             0x0080
+#define TLV320AIC23_LHV_DEFAULT                0x0079
+#define TLV320AIC23_LHV_MAX            0x007f
+#define TLV320AIC23_LHV_MIN            0x0000
+
+/* Analog audio path control register */
+#define TLV320AIC23_STA_REG(x)         ((x)<<6)
+#define TLV320AIC23_STE_ENABLED                0x0020
+#define TLV320AIC23_DAC_SELECTED       0x0010
+#define TLV320AIC23_BYPASS_ON          0x0008
+#define TLV320AIC23_INSEL_MIC          0x0004
+#define TLV320AIC23_MICM_MUTED         0x0002
+#define TLV320AIC23_MICB_20DB          0x0001
+
+/* Digital audio path control register */
+#define TLV320AIC23_DACM_MUTE          0x0008
+#define TLV320AIC23_DEEMP_32K          0x0002
+#define TLV320AIC23_DEEMP_44K          0x0004
+#define TLV320AIC23_DEEMP_48K          0x0006
+#define TLV320AIC23_ADCHP_ON           0x0001
+
+/* Power control down register */
+#define TLV320AIC23_DEVICE_PWR_OFF     0x0080
+#define TLV320AIC23_CLK_OFF            0x0040
+#define TLV320AIC23_OSC_OFF            0x0020
+#define TLV320AIC23_OUT_OFF            0x0010
+#define TLV320AIC23_DAC_OFF            0x0008
+#define TLV320AIC23_ADC_OFF            0x0004
+#define TLV320AIC23_MIC_OFF            0x0002
+#define TLV320AIC23_LINE_OFF           0x0001
+
+/* Digital audio interface register */
+#define TLV320AIC23_MS_MASTER          0x0040
+#define TLV320AIC23_LRSWAP_ON          0x0020
+#define TLV320AIC23_LRP_ON             0x0010
+#define TLV320AIC23_IWL_16             0x0000
+#define TLV320AIC23_IWL_20             0x0004
+#define TLV320AIC23_IWL_24             0x0008
+#define TLV320AIC23_IWL_32             0x000C
+#define TLV320AIC23_FOR_I2S            0x0002
+#define TLV320AIC23_FOR_DSP            0x0003
+#define TLV320AIC23_FOR_LJUST          0x0001
+
+/* Sample rate control register */
+#define TLV320AIC23_CLKOUT_HALF                0x0080
+#define TLV320AIC23_CLKIN_HALF         0x0040
+#define TLV320AIC23_BOSR_384fs         0x0002  /* BOSR_272fs in USB mode */
+#define TLV320AIC23_USB_CLK_ON         0x0001
+#define TLV320AIC23_SR_MASK             0xf
+#define TLV320AIC23_CLKOUT_SHIFT        7
+#define TLV320AIC23_CLKIN_SHIFT         6
+#define TLV320AIC23_SR_SHIFT            2
+#define TLV320AIC23_BOSR_SHIFT          1
+
+/* Digital interface register */
+#define TLV320AIC23_ACT_ON             0x0001
+
+/*
+ * AUDIO related MACROS
+ */
+
+#define TLV320AIC23_DEFAULT_OUT_VOL    0x70
+#define TLV320AIC23_DEFAULT_IN_VOLUME  0x10
+
+#define TLV320AIC23_OUT_VOL_MIN                TLV320AIC23_LHV_MIN
+#define TLV320AIC23_OUT_VOL_MAX                TLV320AIC23_LHV_MAX
+#define TLV320AIC23_OUT_VO_RANGE       (TLV320AIC23_OUT_VOL_MAX - \
+                                       TLV320AIC23_OUT_VOL_MIN)
+#define TLV320AIC23_OUT_VOL_MASK       TLV320AIC23_OUT_VOL_MAX
+
+#define TLV320AIC23_IN_VOL_MIN         TLV320AIC23_LIV_MIN
+#define TLV320AIC23_IN_VOL_MAX         TLV320AIC23_LIV_MAX
+#define TLV320AIC23_IN_VOL_RANGE       (TLV320AIC23_IN_VOL_MAX - \
+                                       TLV320AIC23_IN_VOL_MIN)
+#define TLV320AIC23_IN_VOL_MASK                TLV320AIC23_IN_VOL_MAX
+
+#define TLV320AIC23_SIDETONE_MASK      0x1c0
+#define TLV320AIC23_SIDETONE_0         0x100
+#define TLV320AIC23_SIDETONE_6         0x000
+#define TLV320AIC23_SIDETONE_9         0x040
+#define TLV320AIC23_SIDETONE_12                0x080
+#define TLV320AIC23_SIDETONE_18                0x0c0
+
+extern struct snd_soc_dai tlv320aic23_dai;
+extern struct snd_soc_codec_device soc_codec_dev_tlv320aic23;
+
+#endif /* _TLV320AIC23_H */
index 566a427c928f18085101add5e5990736101850dc..05336ed7e4935fdbd0d9f27a1f77e3b0c5c0bef2 100644 (file)
@@ -48,7 +48,6 @@
 
 #include "tlv320aic3x.h"
 
-#define AUDIO_NAME "aic3x"
 #define AIC3X_VERSION "0.2"
 
 /* codec private data */
@@ -991,7 +990,7 @@ EXPORT_SYMBOL_GPL(aic3x_headset_detected);
                         SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
 
 struct snd_soc_dai aic3x_dai = {
-       .name = "aic3x",
+       .name = "tlv320aic3x",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 1,
@@ -1055,7 +1054,7 @@ static int aic3x_init(struct snd_soc_device *socdev)
        struct aic3x_setup_data *setup = socdev->codec_data;
        int reg, ret = 0;
 
-       codec->name = "aic3x";
+       codec->name = "tlv320aic3x";
        codec->owner = THIS_MODULE;
        codec->read = aic3x_read_reg_cache;
        codec->write = aic3x_write;
index d206d7f892b68b8c0103bc5337b27e5b460b62d2..a69ee72a7af553ca3f36d03d2c63288d97914232 100644 (file)
@@ -36,7 +36,6 @@
 #include "uda1380.h"
 
 #define UDA1380_VERSION "0.6"
-#define AUDIO_NAME "uda1380"
 
 /*
  * uda1380 register cache
index 9a37c8d95ed2475892f75cbef7a6ca43fc3e1533..d8ca2da8d634e5e2a827339f3f3939d196d89941 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright 2006 Wolfson Microelectronics PLC.
  *
- * Author: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
  *
  * 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
@@ -18,6 +18,7 @@
 #include <linux/pm.h>
 #include <linux/i2c.h>
 #include <linux/platform_device.h>
+#include <linux/spi/spi.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -27,7 +28,6 @@
 
 #include "wm8510.h"
 
-#define AUDIO_NAME "wm8510"
 #define WM8510_VERSION "0.6"
 
 struct snd_soc_codec_device soc_codec_dev_wm8510;
@@ -55,6 +55,9 @@ static const u16 wm8510_reg[WM8510_CACHEREGNUM] = {
        0x0001,
 };
 
+#define WM8510_POWER1_BIASEN  0x08
+#define WM8510_POWER1_BUFIOEN 0x10
+
 /*
  * read wm8510 register cache
  */
@@ -224,9 +227,9 @@ SND_SOC_DAPM_PGA("SpkN Out", WM8510_POWER3, 5, 0, NULL, 0),
 SND_SOC_DAPM_PGA("SpkP Out", WM8510_POWER3, 6, 0, NULL, 0),
 SND_SOC_DAPM_PGA("Mono Out", WM8510_POWER3, 7, 0, NULL, 0),
 
-SND_SOC_DAPM_PGA("Mic PGA", WM8510_POWER2, 2, 0,
-                &wm8510_micpga_controls[0],
-                ARRAY_SIZE(wm8510_micpga_controls)),
+SND_SOC_DAPM_MIXER("Mic PGA", WM8510_POWER2, 2, 0,
+                  &wm8510_micpga_controls[0],
+                  ARRAY_SIZE(wm8510_micpga_controls)),
 SND_SOC_DAPM_MIXER("Boost Mixer", WM8510_POWER2, 4, 0,
        &wm8510_boost_controls[0],
        ARRAY_SIZE(wm8510_boost_controls)),
@@ -526,23 +529,35 @@ static int wm8510_mute(struct snd_soc_dai *dai, int mute)
 static int wm8510_set_bias_level(struct snd_soc_codec *codec,
        enum snd_soc_bias_level level)
 {
+       u16 power1 = wm8510_read_reg_cache(codec, WM8510_POWER1) & ~0x3;
 
        switch (level) {
        case SND_SOC_BIAS_ON:
-               wm8510_write(codec, WM8510_POWER1, 0x1ff);
-               wm8510_write(codec, WM8510_POWER2, 0x1ff);
-               wm8510_write(codec, WM8510_POWER3, 0x1ff);
-               break;
        case SND_SOC_BIAS_PREPARE:
+               power1 |= 0x1;  /* VMID 50k */
+               wm8510_write(codec, WM8510_POWER1, power1);
+               break;
+
        case SND_SOC_BIAS_STANDBY:
+               power1 |= WM8510_POWER1_BIASEN | WM8510_POWER1_BUFIOEN;
+
+               if (codec->bias_level == SND_SOC_BIAS_OFF) {
+                       /* Initial cap charge at VMID 5k */
+                       wm8510_write(codec, WM8510_POWER1, power1 | 0x3);
+                       mdelay(100);
+               }
+
+               power1 |= 0x2;  /* VMID 500k */
+               wm8510_write(codec, WM8510_POWER1, power1);
                break;
+
        case SND_SOC_BIAS_OFF:
-               /* everything off, dac mute, inactive */
-               wm8510_write(codec, WM8510_POWER1, 0x0);
-               wm8510_write(codec, WM8510_POWER2, 0x0);
-               wm8510_write(codec, WM8510_POWER3, 0x0);
+               wm8510_write(codec, WM8510_POWER1, 0);
+               wm8510_write(codec, WM8510_POWER2, 0);
+               wm8510_write(codec, WM8510_POWER3, 0);
                break;
        }
+
        codec->bias_level = level;
        return 0;
 }
@@ -640,6 +655,7 @@ static int wm8510_init(struct snd_soc_device *socdev)
        }
 
        /* power on device */
+       codec->bias_level = SND_SOC_BIAS_OFF;
        wm8510_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
        wm8510_add_controls(codec);
        wm8510_add_widgets(codec);
@@ -747,6 +763,62 @@ err_driver:
 }
 #endif
 
+#if defined(CONFIG_SPI_MASTER)
+static int __devinit wm8510_spi_probe(struct spi_device *spi)
+{
+       struct snd_soc_device *socdev = wm8510_socdev;
+       struct snd_soc_codec *codec = socdev->codec;
+       int ret;
+
+       codec->control_data = spi;
+
+       ret = wm8510_init(socdev);
+       if (ret < 0)
+               dev_err(&spi->dev, "failed to initialise WM8510\n");
+
+       return ret;
+}
+
+static int __devexit wm8510_spi_remove(struct spi_device *spi)
+{
+       return 0;
+}
+
+static struct spi_driver wm8510_spi_driver = {
+       .driver = {
+               .name   = "wm8510",
+               .bus    = &spi_bus_type,
+               .owner  = THIS_MODULE,
+       },
+       .probe          = wm8510_spi_probe,
+       .remove         = __devexit_p(wm8510_spi_remove),
+};
+
+static int wm8510_spi_write(struct spi_device *spi, const char *data, int len)
+{
+       struct spi_transfer t;
+       struct spi_message m;
+       u8 msg[2];
+
+       if (len <= 0)
+               return 0;
+
+       msg[0] = data[0];
+       msg[1] = data[1];
+
+       spi_message_init(&m);
+       memset(&t, 0, (sizeof t));
+
+       t.tx_buf = &msg[0];
+       t.len = len;
+
+       spi_message_add_tail(&t, &m);
+       spi_sync(spi, &m);
+
+       return len;
+}
+#endif /* CONFIG_SPI_MASTER */
+
 static int wm8510_probe(struct platform_device *pdev)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
@@ -772,8 +844,14 @@ static int wm8510_probe(struct platform_device *pdev)
                codec->hw_write = (hw_write_t)i2c_master_send;
                ret = wm8510_add_i2c_device(pdev, setup);
        }
-#else
-       /* Add other interfaces here */
+#endif
+#if defined(CONFIG_SPI_MASTER)
+       if (setup->spi) {
+               codec->hw_write = (hw_write_t)wm8510_spi_write;
+               ret = spi_register_driver(&wm8510_spi_driver);
+               if (ret != 0)
+                       printk(KERN_ERR "can't add spi driver");
+       }
 #endif
 
        if (ret != 0)
@@ -795,6 +873,9 @@ static int wm8510_remove(struct platform_device *pdev)
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        i2c_unregister_device(codec->control_data);
        i2c_del_driver(&wm8510_i2c_driver);
+#endif
+#if defined(CONFIG_SPI_MASTER)
+       spi_unregister_driver(&wm8510_spi_driver);
 #endif
        kfree(codec);
 
index c53683960456ad2a568c3ae44eea7c9095e7723b..bdefcf5c69ff2a9ed57e160843710467d19d33d0 100644 (file)
@@ -94,6 +94,7 @@
 #define WM8510_MCLKDIV_12      (7 << 5)
 
 struct wm8510_setup_data {
+       int spi;
        int i2c_bus;
        unsigned short i2c_address;
 };
index df1ffbe305bf3875a4daa9f22c9ff709a6370bde..627ebfb4209b72b786ad66f992b0659491f8f74d 100644 (file)
@@ -18,7 +18,6 @@
 
 #include <linux/module.h>
 #include <linux/moduleparam.h>
-#include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/delay.h>
@@ -36,7 +35,6 @@
 
 #include "wm8580.h"
 
-#define AUDIO_NAME "wm8580"
 #define WM8580_VERSION "0.1"
 
 struct pll_state {
index 7b64d9a7ff76408092520d614c1601dbb901c7be..7f8a7e36b33e9124d0c3d924301d9cccb6cb9c5f 100644 (file)
@@ -29,7 +29,6 @@
 
 #include "wm8731.h"
 
-#define AUDIO_NAME "wm8731"
 #define WM8731_VERSION "0.13"
 
 struct snd_soc_codec_device soc_codec_dev_wm8731;
index 4892e398a5982fa89b87ecbd1d2ceaa6fdc3af53..9b7296ee5b08fa541c6dfdbc44f9b5b8b31f92d6 100644 (file)
@@ -29,7 +29,6 @@
 
 #include "wm8750.h"
 
-#define AUDIO_NAME "WM8750"
 #define WM8750_VERSION "0.12"
 
 /* codec private data */
index 8c4df44f334582b2fa23a8be42a0ecdea472c1c0..d426eaa2218575b75004a48f86cfe9079d84fa21 100644 (file)
@@ -2,8 +2,7 @@
  * wm8753.c  --  WM8753 ALSA Soc Audio driver
  *
  * Copyright 2003 Wolfson Microelectronics PLC.
- * Author: Liam Girdwood
- *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
  *
  *  This program is free software; you can redistribute  it and/or modify it
  *  under  the terms of  the GNU General  Public License as published by the
@@ -40,6 +39,7 @@
 #include <linux/pm.h>
 #include <linux/i2c.h>
 #include <linux/platform_device.h>
+#include <linux/spi/spi.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -51,7 +51,6 @@
 
 #include "wm8753.h"
 
-#define AUDIO_NAME "wm8753"
 #define WM8753_VERSION "0.16"
 
 static int caps_charge = 2000;
@@ -1719,6 +1718,63 @@ err_driver:
 }
 #endif
 
+#if defined(CONFIG_SPI_MASTER)
+static int __devinit wm8753_spi_probe(struct spi_device *spi)
+{
+       struct snd_soc_device *socdev = wm8753_socdev;
+       struct snd_soc_codec *codec = socdev->codec;
+       int ret;
+
+       codec->control_data = spi;
+
+       ret = wm8753_init(socdev);
+       if (ret < 0)
+               dev_err(&spi->dev, "failed to initialise WM8753\n");
+
+       return ret;
+}
+
+static int __devexit wm8753_spi_remove(struct spi_device *spi)
+{
+       return 0;
+}
+
+static struct spi_driver wm8753_spi_driver = {
+       .driver = {
+               .name   = "wm8753",
+               .bus    = &spi_bus_type,
+               .owner  = THIS_MODULE,
+       },
+       .probe          = wm8753_spi_probe,
+       .remove         = __devexit_p(wm8753_spi_remove),
+};
+
+static int wm8753_spi_write(struct spi_device *spi, const char *data, int len)
+{
+       struct spi_transfer t;
+       struct spi_message m;
+       u8 msg[2];
+
+       if (len <= 0)
+               return 0;
+
+       msg[0] = data[0];
+       msg[1] = data[1];
+
+       spi_message_init(&m);
+       memset(&t, 0, (sizeof t));
+
+       t.tx_buf = &msg[0];
+       t.len = len;
+
+       spi_message_add_tail(&t, &m);
+       spi_sync(spi, &m);
+
+       return len;
+}
+#endif
+
+
 static int wm8753_probe(struct platform_device *pdev)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
@@ -1753,8 +1809,14 @@ static int wm8753_probe(struct platform_device *pdev)
                codec->hw_write = (hw_write_t)i2c_master_send;
                ret = wm8753_add_i2c_device(pdev, setup);
        }
-#else
-               /* Add other interfaces here */
+#endif
+#if defined(CONFIG_SPI_MASTER)
+       if (setup->spi) {
+               codec->hw_write = (hw_write_t)wm8753_spi_write;
+               ret = spi_register_driver(&wm8753_spi_driver);
+               if (ret != 0)
+                       printk(KERN_ERR "can't add spi driver");
+       }
 #endif
 
        if (ret != 0) {
@@ -1797,6 +1859,9 @@ static int wm8753_remove(struct platform_device *pdev)
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        i2c_unregister_device(codec->control_data);
        i2c_del_driver(&wm8753_i2c_driver);
+#endif
+#if defined(CONFIG_SPI_MASTER)
+       spi_unregister_driver(&wm8753_spi_driver);
 #endif
        kfree(codec->private_data);
        kfree(codec);
index 7defde069f1df92793c254f49c305351db3d8b86..f55704ce931b44e135b8038967eaebf751dbf632 100644 (file)
@@ -2,8 +2,7 @@
  * wm8753.h  --  audio driver for WM8753
  *
  * Copyright 2003 Wolfson Microelectronics PLC.
- * Author: Liam Girdwood
- *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
  *
  *  This program is free software; you can redistribute  it and/or modify it
  *  under  the terms of  the GNU General  Public License as published by the
@@ -79,6 +78,7 @@
 #define WM8753_ADCTL2          0x3f
 
 struct wm8753_setup_data {
+       int spi;
        int i2c_bus;
        unsigned short i2c_address;
 };
index 0b8c6d38b48f4253db572b422bec4d04da9bedb5..3b326c9b55866bba7a81c1421329026bed290247 100644 (file)
@@ -18,7 +18,6 @@
 
 #include <linux/module.h>
 #include <linux/moduleparam.h>
-#include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/delay.h>
index a3f54ec4226eb554248c75133508a5d7d21701f2..ce40d78776058456782f5d723152250bfc79e681 100644 (file)
@@ -653,14 +653,14 @@ static const struct snd_kcontrol_new wm8903_snd_controls[] = {
 
 /* Input PGAs - No TLV since the scale depends on PGA mode */
 SOC_SINGLE("Left Input PGA Switch", WM8903_ANALOGUE_LEFT_INPUT_0,
-          7, 1, 0),
+          7, 1, 1),
 SOC_SINGLE("Left Input PGA Volume", WM8903_ANALOGUE_LEFT_INPUT_0,
           0, 31, 0),
 SOC_SINGLE("Left Input PGA Common Mode Switch", WM8903_ANALOGUE_LEFT_INPUT_1,
           6, 1, 0),
 
 SOC_SINGLE("Right Input PGA Switch", WM8903_ANALOGUE_RIGHT_INPUT_0,
-          7, 1, 0),
+          7, 1, 1),
 SOC_SINGLE("Right Input PGA Volume", WM8903_ANALOGUE_RIGHT_INPUT_0,
           0, 31, 0),
 SOC_SINGLE("Right Input PGA Common Mode Switch", WM8903_ANALOGUE_RIGHT_INPUT_1,
index 974a4cd0f3fdbd6ce0845e8ea7fcb954e345ecd9..f41a578ddd4fabe908053cee4b273a43155b0e77 100644 (file)
@@ -29,7 +29,6 @@
 
 #include "wm8971.h"
 
-#define AUDIO_NAME "wm8971"
 #define WM8971_VERSION "0.9"
 
 #define        WM8971_REG_COUNT                43
index 63410d7b5efb3623c8e92585ac51fb9ff8737606..572d22b0880b5b1f1033e244cee6269831cd9216 100644 (file)
@@ -30,7 +30,6 @@
 
 #include "wm8990.h"
 
-#define AUDIO_NAME "wm8990"
 #define WM8990_VERSION "0.2"
 
 /* codec private data */
index 2f1c91b1d5567feb6fc3aea44eece7a3f00dd158..ffb471e420e2e76718f931420135c8b99cf21864 100644 (file)
@@ -2,8 +2,7 @@
  * wm9712.c  --  ALSA Soc WM9712 codec support
  *
  * Copyright 2006 Wolfson Microelectronics PLC.
- * Author: Liam Girdwood
- *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
  *
  *  This program is free software; you can redistribute  it and/or modify it
  *  under  the terms of  the GNU General  Public License as published by the
index 441d0580db1f75adf212ee40a882cd4ca47fb4c0..aba402b3c99994a95489bde9e526da23f7d4ea69 100644 (file)
@@ -2,8 +2,7 @@
  * wm9713.c  --  ALSA Soc WM9713 codec support
  *
  * Copyright 2006 Wolfson Microelectronics PLC.
- * Author: Liam Girdwood
- *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
  *
  *  This program is free software; you can redistribute  it and/or modify it
  *  under  the terms of  the GNU General  Public License as published by the
index aea27e70043cf8f687884227c117ceed224c98f4..8b7766b998d7de431bd30d18d32569019a116d28 100644 (file)
@@ -13,3 +13,11 @@ config SND_OMAP_SOC_N810
        select SND_SOC_TLV320AIC3X
        help
          Say Y if you want to add support for SoC audio on Nokia N810.
+
+config SND_OMAP_SOC_OSK5912
+       tristate "SoC Audio support for omap osk5912"
+       depends on SND_OMAP_SOC && MACH_OMAP_OSK
+       select SND_OMAP_SOC_MCBSP
+       select SND_SOC_TLV320AIC23
+       help
+         Say Y if you want to add support for SoC audio on osk5912.
index d8d8d58075e3ee4c0b362eadeee9fce1b43cc2d3..e09d1f297f644c856c16250dc7cdc407bd6f7e6f 100644 (file)
@@ -7,5 +7,7 @@ obj-$(CONFIG_SND_OMAP_SOC_MCBSP) += snd-soc-omap-mcbsp.o
 
 # OMAP Machine Support
 snd-soc-n810-objs := n810.o
+snd-soc-osk5912-objs := osk5912.o
 
 obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o
+obj-$(CONFIG_SND_OMAP_SOC_OSK5912) += snd-soc-osk5912.o
index d166b6b2a60dd9b78ade26cb76532cbe1b3c30a8..fae3ad36e0bfc3e03606561c48c0c54bb7d192b6 100644 (file)
@@ -247,9 +247,9 @@ static int n810_aic33_init(struct snd_soc_codec *codec)
        int i, err;
 
        /* Not connected */
-       snd_soc_dapm_disable_pin(codec, "MONO_LOUT");
-       snd_soc_dapm_disable_pin(codec, "HPLCOM");
-       snd_soc_dapm_disable_pin(codec, "HPRCOM");
+       snd_soc_dapm_nc_pin(codec, "MONO_LOUT");
+       snd_soc_dapm_nc_pin(codec, "HPLCOM");
+       snd_soc_dapm_nc_pin(codec, "HPRCOM");
 
        /* Add N810 specific controls */
        for (i = 0; i < ARRAY_SIZE(aic33_n810_controls); i++) {
index 35310e16d7f3658623fdf9755ae6df7190688a1e..0a063a98a6613820295419a5cab10bd09a8dc338 100644 (file)
@@ -59,12 +59,7 @@ static struct omap_mcbsp_data mcbsp_data[NUM_LINKS];
  * Stream DMA parameters. DMA request line and port address are set runtime
  * since they are different between OMAP1 and later OMAPs
  */
-static struct omap_pcm_dma_data omap_mcbsp_dai_dma_params[NUM_LINKS][2] = {
-{
-       { .name         = "I2S PCM Stereo out", },
-       { .name         = "I2S PCM Stereo in", },
-},
-};
+static struct omap_pcm_dma_data omap_mcbsp_dai_dma_params[NUM_LINKS][2];
 
 #if defined(CONFIG_ARCH_OMAP15XX) || defined(CONFIG_ARCH_OMAP16XX)
 static const int omap1_dma_reqs[][2] = {
@@ -84,11 +79,22 @@ static const unsigned long omap1_mcbsp_port[][2] = {
 static const int omap1_dma_reqs[][2] = {};
 static const unsigned long omap1_mcbsp_port[][2] = {};
 #endif
-#if defined(CONFIG_ARCH_OMAP2420)
-static const int omap2420_dma_reqs[][2] = {
+
+#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
+static const int omap24xx_dma_reqs[][2] = {
        { OMAP24XX_DMA_MCBSP1_TX, OMAP24XX_DMA_MCBSP1_RX },
        { OMAP24XX_DMA_MCBSP2_TX, OMAP24XX_DMA_MCBSP2_RX },
+#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP34XX)
+       { OMAP24XX_DMA_MCBSP3_TX, OMAP24XX_DMA_MCBSP3_RX },
+       { OMAP24XX_DMA_MCBSP4_TX, OMAP24XX_DMA_MCBSP4_RX },
+       { OMAP24XX_DMA_MCBSP5_TX, OMAP24XX_DMA_MCBSP5_RX },
+#endif
 };
+#else
+static const int omap24xx_dma_reqs[][2] = {};
+#endif
+
+#if defined(CONFIG_ARCH_OMAP2420)
 static const unsigned long omap2420_mcbsp_port[][2] = {
        { OMAP24XX_MCBSP1_BASE + OMAP_MCBSP_REG_DXR1,
          OMAP24XX_MCBSP1_BASE + OMAP_MCBSP_REG_DRR1 },
@@ -96,10 +102,43 @@ static const unsigned long omap2420_mcbsp_port[][2] = {
          OMAP24XX_MCBSP2_BASE + OMAP_MCBSP_REG_DRR1 },
 };
 #else
-static const int omap2420_dma_reqs[][2] = {};
 static const unsigned long omap2420_mcbsp_port[][2] = {};
 #endif
 
+#if defined(CONFIG_ARCH_OMAP2430)
+static const unsigned long omap2430_mcbsp_port[][2] = {
+       { OMAP24XX_MCBSP1_BASE + OMAP_MCBSP_REG_DXR,
+         OMAP24XX_MCBSP1_BASE + OMAP_MCBSP_REG_DRR },
+       { OMAP24XX_MCBSP2_BASE + OMAP_MCBSP_REG_DXR,
+         OMAP24XX_MCBSP2_BASE + OMAP_MCBSP_REG_DRR },
+       { OMAP2430_MCBSP3_BASE + OMAP_MCBSP_REG_DXR,
+         OMAP2430_MCBSP3_BASE + OMAP_MCBSP_REG_DRR },
+       { OMAP2430_MCBSP4_BASE + OMAP_MCBSP_REG_DXR,
+         OMAP2430_MCBSP4_BASE + OMAP_MCBSP_REG_DRR },
+       { OMAP2430_MCBSP5_BASE + OMAP_MCBSP_REG_DXR,
+         OMAP2430_MCBSP5_BASE + OMAP_MCBSP_REG_DRR },
+};
+#else
+static const unsigned long omap2430_mcbsp_port[][2] = {};
+#endif
+
+#if defined(CONFIG_ARCH_OMAP34XX)
+static const unsigned long omap34xx_mcbsp_port[][2] = {
+       { OMAP34XX_MCBSP1_BASE + OMAP_MCBSP_REG_DXR,
+         OMAP34XX_MCBSP1_BASE + OMAP_MCBSP_REG_DRR },
+       { OMAP34XX_MCBSP2_BASE + OMAP_MCBSP_REG_DXR,
+         OMAP34XX_MCBSP2_BASE + OMAP_MCBSP_REG_DRR },
+       { OMAP34XX_MCBSP3_BASE + OMAP_MCBSP_REG_DXR,
+         OMAP34XX_MCBSP3_BASE + OMAP_MCBSP_REG_DRR },
+       { OMAP34XX_MCBSP4_BASE + OMAP_MCBSP_REG_DXR,
+         OMAP34XX_MCBSP4_BASE + OMAP_MCBSP_REG_DRR },
+       { OMAP34XX_MCBSP5_BASE + OMAP_MCBSP_REG_DXR,
+         OMAP34XX_MCBSP5_BASE + OMAP_MCBSP_REG_DRR },
+};
+#else
+static const unsigned long omap34xx_mcbsp_port[][2] = {};
+#endif
+
 static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
@@ -167,14 +206,19 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
                dma = omap1_dma_reqs[bus_id][substream->stream];
                port = omap1_mcbsp_port[bus_id][substream->stream];
        } else if (cpu_is_omap2420()) {
-               dma = omap2420_dma_reqs[bus_id][substream->stream];
+               dma = omap24xx_dma_reqs[bus_id][substream->stream];
                port = omap2420_mcbsp_port[bus_id][substream->stream];
+       } else if (cpu_is_omap2430()) {
+               dma = omap24xx_dma_reqs[bus_id][substream->stream];
+               port = omap2430_mcbsp_port[bus_id][substream->stream];
+       } else if (cpu_is_omap343x()) {
+               dma = omap24xx_dma_reqs[bus_id][substream->stream];
+               port = omap34xx_mcbsp_port[bus_id][substream->stream];
        } else {
-               /*
-                * TODO: Add support for 2430 and 3430
-                */
                return -ENODEV;
        }
+       omap_mcbsp_dai_dma_params[id][substream->stream].name =
+               substream->stream ? "Audio Capture" : "Audio Playback";
        omap_mcbsp_dai_dma_params[id][substream->stream].dma_req = dma;
        omap_mcbsp_dai_dma_params[id][substream->stream].port_addr = port;
        cpu_dai->dma_data = &omap_mcbsp_dai_dma_params[id][substream->stream];
@@ -245,6 +289,11 @@ static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai,
                regs->rcr2      |= RDATDLY(1);
                regs->xcr2      |= XDATDLY(1);
                break;
+       case SND_SOC_DAIFMT_DSP_A:
+               /* 0-bit data delay */
+               regs->rcr2      |= RDATDLY(0);
+               regs->xcr2      |= XDATDLY(0);
+               break;
        default:
                /* Unsupported data format */
                return -EINVAL;
@@ -310,7 +359,7 @@ static int omap_mcbsp_dai_set_clks_src(struct omap_mcbsp_data *mcbsp_data,
                                       int clk_id)
 {
        int sel_bit;
-       u16 reg;
+       u16 reg, reg_devconf1 = OMAP243X_CONTROL_DEVCONF1;
 
        if (cpu_class_is_omap1()) {
                /* OMAP1's can use only external source clock */
@@ -320,6 +369,12 @@ static int omap_mcbsp_dai_set_clks_src(struct omap_mcbsp_data *mcbsp_data,
                        return 0;
        }
 
+       if (cpu_is_omap2420() && mcbsp_data->bus_id > 1)
+               return -EINVAL;
+
+       if (cpu_is_omap343x())
+               reg_devconf1 = OMAP343X_CONTROL_DEVCONF1;
+
        switch (mcbsp_data->bus_id) {
        case 0:
                reg = OMAP2_CONTROL_DEVCONF0;
@@ -329,20 +384,26 @@ static int omap_mcbsp_dai_set_clks_src(struct omap_mcbsp_data *mcbsp_data,
                reg = OMAP2_CONTROL_DEVCONF0;
                sel_bit = 6;
                break;
-       /* TODO: Support for ports 3 - 5 in OMAP2430 and OMAP34xx */
+       case 2:
+               reg = reg_devconf1;
+               sel_bit = 0;
+               break;
+       case 3:
+               reg = reg_devconf1;
+               sel_bit = 2;
+               break;
+       case 4:
+               reg = reg_devconf1;
+               sel_bit = 4;
+               break;
        default:
                return -EINVAL;
        }
 
-       if (cpu_class_is_omap2()) {
-               if (clk_id == OMAP_MCBSP_SYSCLK_CLKS_FCLK) {
-                       omap_ctrl_writel(omap_ctrl_readl(reg) &
-                                        ~(1 << sel_bit), reg);
-               } else {
-                       omap_ctrl_writel(omap_ctrl_readl(reg) |
-                                        (1 << sel_bit), reg);
-               }
-       }
+       if (clk_id == OMAP_MCBSP_SYSCLK_CLKS_FCLK)
+               omap_ctrl_writel(omap_ctrl_readl(reg) & ~(1 << sel_bit), reg);
+       else
+               omap_ctrl_writel(omap_ctrl_readl(reg) | (1 << sel_bit), reg);
 
        return 0;
 }
@@ -376,37 +437,49 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
        return err;
 }
 
-struct snd_soc_dai omap_mcbsp_dai[NUM_LINKS] = {
-{
-       .name = "omap-mcbsp-dai",
-       .id = 0,
-       .type = SND_SOC_DAI_I2S,
-       .playback = {
-               .channels_min = 2,
-               .channels_max = 2,
-               .rates = OMAP_MCBSP_RATES,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,
-       },
-       .capture = {
-               .channels_min = 2,
-               .channels_max = 2,
-               .rates = OMAP_MCBSP_RATES,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,
-       },
-       .ops = {
-               .startup = omap_mcbsp_dai_startup,
-               .shutdown = omap_mcbsp_dai_shutdown,
-               .trigger = omap_mcbsp_dai_trigger,
-               .hw_params = omap_mcbsp_dai_hw_params,
-       },
-       .dai_ops = {
-               .set_fmt = omap_mcbsp_dai_set_dai_fmt,
-               .set_clkdiv = omap_mcbsp_dai_set_clkdiv,
-               .set_sysclk = omap_mcbsp_dai_set_dai_sysclk,
-       },
-       .private_data = &mcbsp_data[0].bus_id,
-},
+#define OMAP_MCBSP_DAI_BUILDER(link_id)                                \
+{                                                              \
+       .name = "omap-mcbsp-dai-(link_id)",                     \
+       .id = (link_id),                                        \
+       .type = SND_SOC_DAI_I2S,                                \
+       .playback = {                                           \
+               .channels_min = 2,                              \
+               .channels_max = 2,                              \
+               .rates = OMAP_MCBSP_RATES,                      \
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,             \
+       },                                                      \
+       .capture = {                                            \
+               .channels_min = 2,                              \
+               .channels_max = 2,                              \
+               .rates = OMAP_MCBSP_RATES,                      \
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,             \
+       },                                                      \
+       .ops = {                                                \
+               .startup = omap_mcbsp_dai_startup,              \
+               .shutdown = omap_mcbsp_dai_shutdown,            \
+               .trigger = omap_mcbsp_dai_trigger,              \
+               .hw_params = omap_mcbsp_dai_hw_params,          \
+       },                                                      \
+       .dai_ops = {                                            \
+               .set_fmt = omap_mcbsp_dai_set_dai_fmt,          \
+               .set_clkdiv = omap_mcbsp_dai_set_clkdiv,        \
+               .set_sysclk = omap_mcbsp_dai_set_dai_sysclk,    \
+       },                                                      \
+       .private_data = &mcbsp_data[(link_id)].bus_id,          \
+}
+
+struct snd_soc_dai omap_mcbsp_dai[] = {
+       OMAP_MCBSP_DAI_BUILDER(0),
+       OMAP_MCBSP_DAI_BUILDER(1),
+#if NUM_LINKS >= 3
+       OMAP_MCBSP_DAI_BUILDER(2),
+#endif
+#if NUM_LINKS == 5
+       OMAP_MCBSP_DAI_BUILDER(3),
+       OMAP_MCBSP_DAI_BUILDER(4),
+#endif
 };
+
 EXPORT_SYMBOL_GPL(omap_mcbsp_dai);
 
 MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@nokia.com>");
index ed8afb55067173fc4969b2984ae20e10f5cabdea..df7ad13ba73d14711ca8aff42067e317b1639d1e 100644 (file)
@@ -38,11 +38,17 @@ enum omap_mcbsp_div {
        OMAP_MCBSP_CLKGDV,              /* Sample rate generator divider */
 };
 
-/*
- * REVISIT: Preparation for the ASoC v2. Let the number of available links to
- * be same than number of McBSP ports found in OMAP(s) we are compiling for.
- */
-#define NUM_LINKS      1
+#if defined(CONFIG_ARCH_OMAP2420)
+#define NUM_LINKS      2
+#endif
+#if defined(CONFIG_ARCH_OMAP15XX) || defined(CONFIG_ARCH_OMAP16XX)
+#undef  NUM_LINKS
+#define NUM_LINKS      3
+#endif
+#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP34XX)
+#undef  NUM_LINKS
+#define NUM_LINKS      5
+#endif
 
 extern struct snd_soc_dai omap_mcbsp_dai[NUM_LINKS];
 
index 690bfeaec4a0ee3b157b0ccb7a7ea1a1ea5e4189..e9084fdd2082efcbc14695e801ec6ad89ff66599 100644 (file)
@@ -97,7 +97,7 @@ static int omap_pcm_hw_params(struct snd_pcm_substream *substream,
        prtd->dma_data = dma_data;
        err = omap_request_dma(dma_data->dma_req, dma_data->name,
                               omap_pcm_dma_irq, substream, &prtd->dma_ch);
-       if (!cpu_is_omap1510()) {
+       if (!err & !cpu_is_omap1510()) {
                /*
                 * Link channel with itself so DMA doesn't need any
                 * reprogramming while looping the buffer
@@ -147,12 +147,14 @@ static int omap_pcm_prepare(struct snd_pcm_substream *substream)
                dma_params.src_or_dst_synch     = OMAP_DMA_DST_SYNC;
                dma_params.src_start            = runtime->dma_addr;
                dma_params.dst_start            = dma_data->port_addr;
+               dma_params.dst_port             = OMAP_DMA_PORT_MPUI;
        } else {
                dma_params.src_amode            = OMAP_DMA_AMODE_CONSTANT;
                dma_params.dst_amode            = OMAP_DMA_AMODE_POST_INC;
                dma_params.src_or_dst_synch     = OMAP_DMA_SRC_SYNC;
                dma_params.src_start            = dma_data->port_addr;
                dma_params.dst_start            = runtime->dma_addr;
+               dma_params.src_port             = OMAP_DMA_PORT_MPUI;
        }
        /*
         * Set DMA transfer frame size equal to ALSA period size and frame
diff --git a/sound/soc/omap/osk5912.c b/sound/soc/omap/osk5912.c
new file mode 100644 (file)
index 0000000..0fe7337
--- /dev/null
@@ -0,0 +1,232 @@
+/*
+ * osk5912.c  --  SoC audio for OSK 5912
+ *
+ * Copyright (C) 2008 Mistral Solutions
+ *
+ * Contact: Arun KS  <arunks@mistralsolutions.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <asm/mach-types.h>
+#include <mach/hardware.h>
+#include <linux/gpio.h>
+#include <mach/mcbsp.h>
+
+#include "omap-mcbsp.h"
+#include "omap-pcm.h"
+#include "../codecs/tlv320aic23.h"
+
+#define CODEC_CLOCK    12000000
+
+static struct clk *tlv320aic23_mclk;
+
+static int osk_startup(struct snd_pcm_substream *substream)
+{
+       return clk_enable(tlv320aic23_mclk);
+}
+
+static void osk_shutdown(struct snd_pcm_substream *substream)
+{
+       clk_disable(tlv320aic23_mclk);
+}
+
+static int osk_hw_params(struct snd_pcm_substream *substream,
+                        struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       int err;
+
+       /* Set codec DAI configuration */
+       err = snd_soc_dai_set_fmt(codec_dai,
+                                 SND_SOC_DAIFMT_DSP_A |
+                                 SND_SOC_DAIFMT_NB_IF |
+                                 SND_SOC_DAIFMT_CBM_CFM);
+       if (err < 0) {
+               printk(KERN_ERR "can't set codec DAI configuration\n");
+               return err;
+       }
+
+       /* Set cpu DAI configuration */
+       err = snd_soc_dai_set_fmt(cpu_dai,
+                                 SND_SOC_DAIFMT_DSP_A |
+                                 SND_SOC_DAIFMT_NB_IF |
+                                 SND_SOC_DAIFMT_CBM_CFM);
+       if (err < 0) {
+               printk(KERN_ERR "can't set cpu DAI configuration\n");
+               return err;
+       }
+
+       /* Set the codec system clock for DAC and ADC */
+       err =
+           snd_soc_dai_set_sysclk(codec_dai, 0, CODEC_CLOCK, SND_SOC_CLOCK_IN);
+
+       if (err < 0) {
+               printk(KERN_ERR "can't set codec system clock\n");
+               return err;
+       }
+
+       return err;
+}
+
+static struct snd_soc_ops osk_ops = {
+       .startup = osk_startup,
+       .hw_params = osk_hw_params,
+       .shutdown = osk_shutdown,
+};
+
+static const struct snd_soc_dapm_widget tlv320aic23_dapm_widgets[] = {
+       SND_SOC_DAPM_HP("Headphone Jack", NULL),
+       SND_SOC_DAPM_LINE("Line In", NULL),
+       SND_SOC_DAPM_MIC("Mic Jack", NULL),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+       {"Headphone Jack", NULL, "LHPOUT"},
+       {"Headphone Jack", NULL, "RHPOUT"},
+
+       {"LLINEIN", NULL, "Line In"},
+       {"RLINEIN", NULL, "Line In"},
+
+       {"MICIN", NULL, "Mic Jack"},
+};
+
+static int osk_tlv320aic23_init(struct snd_soc_codec *codec)
+{
+
+       /* Add osk5912 specific widgets */
+       snd_soc_dapm_new_controls(codec, tlv320aic23_dapm_widgets,
+                                 ARRAY_SIZE(tlv320aic23_dapm_widgets));
+
+       /* Set up osk5912 specific audio path audio_map */
+       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+
+       snd_soc_dapm_enable_pin(codec, "Headphone Jack");
+       snd_soc_dapm_enable_pin(codec, "Line In");
+       snd_soc_dapm_enable_pin(codec, "Mic Jack");
+
+       snd_soc_dapm_sync(codec);
+
+       return 0;
+}
+
+/* Digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link osk_dai = {
+       .name = "TLV320AIC23",
+       .stream_name = "AIC23",
+       .cpu_dai = &omap_mcbsp_dai[0],
+       .codec_dai = &tlv320aic23_dai,
+       .init = osk_tlv320aic23_init,
+       .ops = &osk_ops,
+};
+
+/* Audio machine driver */
+static struct snd_soc_machine snd_soc_machine_osk = {
+       .name = "OSK5912",
+       .dai_link = &osk_dai,
+       .num_links = 1,
+};
+
+/* Audio subsystem */
+static struct snd_soc_device osk_snd_devdata = {
+       .machine = &snd_soc_machine_osk,
+       .platform = &omap_soc_platform,
+       .codec_dev = &soc_codec_dev_tlv320aic23,
+};
+
+static struct platform_device *osk_snd_device;
+
+static int __init osk_soc_init(void)
+{
+       int err;
+       u32 curRate;
+       struct device *dev;
+
+       if (!(machine_is_omap_osk()))
+               return -ENODEV;
+
+       osk_snd_device = platform_device_alloc("soc-audio", -1);
+       if (!osk_snd_device)
+               return -ENOMEM;
+
+       platform_set_drvdata(osk_snd_device, &osk_snd_devdata);
+       osk_snd_devdata.dev = &osk_snd_device->dev;
+       *(unsigned int *)osk_dai.cpu_dai->private_data = 0;     /* McBSP1 */
+       err = platform_device_add(osk_snd_device);
+       if (err)
+               goto err1;
+
+       dev = &osk_snd_device->dev;
+
+       tlv320aic23_mclk = clk_get(dev, "mclk");
+       if (IS_ERR(tlv320aic23_mclk)) {
+               printk(KERN_ERR "Could not get mclk clock\n");
+               return -ENODEV;
+       }
+
+       if (clk_get_usecount(tlv320aic23_mclk) > 0) {
+               /* MCLK is already in use */
+               printk(KERN_WARNING
+                      "MCLK in use at %d Hz. We change it to %d Hz\n",
+                      (uint) clk_get_rate(tlv320aic23_mclk), CODEC_CLOCK);
+       }
+
+       /*
+        * Configure 12 MHz output on MCLK.
+        */
+       curRate = (uint) clk_get_rate(tlv320aic23_mclk);
+       if (curRate != CODEC_CLOCK) {
+               if (clk_set_rate(tlv320aic23_mclk, CODEC_CLOCK)) {
+                       printk(KERN_ERR "Cannot set MCLK for AIC23 CODEC\n");
+                       err = -ECANCELED;
+                       goto err1;
+               }
+       }
+
+       printk(KERN_INFO "MCLK = %d [%d], usecount = %d\n",
+              (uint) clk_get_rate(tlv320aic23_mclk), CODEC_CLOCK,
+              clk_get_usecount(tlv320aic23_mclk));
+
+       return 0;
+err1:
+       clk_put(tlv320aic23_mclk);
+       platform_device_del(osk_snd_device);
+       platform_device_put(osk_snd_device);
+
+       return err;
+
+}
+
+static void __exit osk_soc_exit(void)
+{
+       platform_device_unregister(osk_snd_device);
+}
+
+module_init(osk_soc_init);
+module_exit(osk_soc_exit);
+
+MODULE_AUTHOR("Arun KS <arunks@mistralsolutions.com>");
+MODULE_DESCRIPTION("ALSA SoC OSK 5912");
+MODULE_LICENSE("GPL");
index 1a8373de7f3a3badc8a58b5f3559186cff21c584..2718eaf7895f39d4db2e5d93e4227400b995b1a7 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright 2005 Wolfson Microelectronics PLC.
  * Copyright 2005 Openedhand Ltd.
  *
- * Authors: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ * Authors: Liam Girdwood <lrg@slimlogic.co.uk>
  *          Richard Purdie <richard@openedhand.com>
  *
  *  This program is free software; you can redistribute  it and/or modify it
@@ -281,8 +281,8 @@ static int corgi_wm8731_init(struct snd_soc_codec *codec)
 {
        int i, err;
 
-       snd_soc_dapm_disable_pin(codec, "LLINEIN");
-       snd_soc_dapm_disable_pin(codec, "RLINEIN");
+       snd_soc_dapm_nc_pin(codec, "LLINEIN");
+       snd_soc_dapm_nc_pin(codec, "RLINEIN");
 
        /* Add corgi specific controls */
        for (i = 0; i < ARRAY_SIZE(wm8731_corgi_controls); i++) {
index d9c3f7b28be212ecdb7cc1bf62ce22d09f2808df..e6ff6929ab4b799f7b9875144681469c15e6d8fe 100644 (file)
@@ -9,7 +9,7 @@
  * Copyright 2005 Wolfson Microelectronics PLC.
  * Copyright 2005 Openedhand Ltd.
  *
- * Authors: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ * Authors: Liam Girdwood <lrg@slimlogic.co.uk>
  *          Richard Purdie <richard@openedhand.com>
  *
  *  This program is free software; you can redistribute  it and/or modify it
index f84f7d8db09a0f19d5eb75089203bd603f25708f..4d9930c52789989313a8a1189bbc99b26160d8b2 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright 2005 Wolfson Microelectronics PLC.
  * Copyright 2005 Openedhand Ltd.
  *
- * Authors: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ * Authors: Liam Girdwood <lrg@slimlogic.co.uk>
  *          Richard Purdie <richard@openedhand.com>
  *
  *  This program is free software; you can redistribute  it and/or modify it
@@ -242,8 +242,8 @@ static int poodle_wm8731_init(struct snd_soc_codec *codec)
 {
        int i, err;
 
-       snd_soc_dapm_disable_pin(codec, "LLINEIN");
-       snd_soc_dapm_disable_pin(codec, "RLINEIN");
+       snd_soc_dapm_nc_pin(codec, "LLINEIN");
+       snd_soc_dapm_nc_pin(codec, "RLINEIN");
        snd_soc_dapm_enable_pin(codec, "MICIN");
 
        /* Add poodle specific controls */
index 2fb58298513b32c88e5cf2f74184db37a883d163..e758034db5c3ba38422e07592b2a933dc3e50b81 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright 2005 Wolfson Microelectronics PLC.
  * Author: Liam Girdwood
- *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ *         lrg@slimlogic.co.uk
  *
  *  This program is free software; you can redistribute  it and/or modify it
  *  under  the terms of  the GNU General  Public License as published by the
@@ -405,6 +405,6 @@ module_init(pxa2xx_i2s_init);
 module_exit(pxa2xx_i2s_exit);
 
 /* Module information */
-MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com");
+MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk");
 MODULE_DESCRIPTION("pxa2xx I2S SoC Interface");
 MODULE_LICENSE("GPL");
index 9a70b00fc30e6d8100c2698b56adad67f2d08594..d307b6757e9550646b565a4cffaac5abc0a02007 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright 2005 Wolfson Microelectronics PLC.
  * Copyright 2005 Openedhand Ltd.
  *
- * Authors: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ * Authors: Liam Girdwood <lrg@slimlogic.co.uk>
  *          Richard Purdie <richard@openedhand.com>
  *
  *  This program is free software; you can redistribute  it and/or modify it
@@ -281,13 +281,13 @@ static int spitz_wm8750_init(struct snd_soc_codec *codec)
        int i, err;
 
        /* NC codec pins */
-       snd_soc_dapm_disable_pin(codec, "RINPUT1");
-       snd_soc_dapm_disable_pin(codec, "LINPUT2");
-       snd_soc_dapm_disable_pin(codec, "RINPUT2");
-       snd_soc_dapm_disable_pin(codec, "LINPUT3");
-       snd_soc_dapm_disable_pin(codec, "RINPUT3");
-       snd_soc_dapm_disable_pin(codec, "OUT3");
-       snd_soc_dapm_disable_pin(codec, "MONO1");
+       snd_soc_dapm_nc_pin(codec, "RINPUT1");
+       snd_soc_dapm_nc_pin(codec, "LINPUT2");
+       snd_soc_dapm_nc_pin(codec, "RINPUT2");
+       snd_soc_dapm_nc_pin(codec, "LINPUT3");
+       snd_soc_dapm_nc_pin(codec, "RINPUT3");
+       snd_soc_dapm_nc_pin(codec, "OUT3");
+       snd_soc_dapm_nc_pin(codec, "MONO1");
 
        /* Add spitz specific controls */
        for (i = 0; i < ARRAY_SIZE(wm8750_spitz_controls); i++) {
index 2baaa750f123013f566fb351e972651a967db382..afefe41b8c46c9f47ae255b14ec1ebed56e3522e 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright 2005 Wolfson Microelectronics PLC.
  * Copyright 2005 Openedhand Ltd.
  *
- * Authors: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ * Authors: Liam Girdwood <lrg@slimlogic.co.uk>
  *          Richard Purdie <richard@openedhand.com>
  *
  *  This program is free software; you can redistribute  it and/or modify it
@@ -190,8 +190,8 @@ static int tosa_ac97_init(struct snd_soc_codec *codec)
 {
        int i, err;
 
-       snd_soc_dapm_disable_pin(codec, "OUT3");
-       snd_soc_dapm_disable_pin(codec, "MONOOUT");
+       snd_soc_dapm_nc_pin(codec, "OUT3");
+       snd_soc_dapm_nc_pin(codec, "MONOOUT");
 
        /* add tosa specific controls */
        for (i = 0; i < ARRAY_SIZE(tosa_controls); i++) {
index 73a50e93a9a222e5296f9a0d5191f9756a275a64..87ddfefcc2fba18b821f3b154fbe03d86e1bf3e7 100644 (file)
@@ -511,21 +511,20 @@ static int neo1973_wm8753_init(struct snd_soc_codec *codec)
        DBG("Entered %s\n", __func__);
 
        /* set up NC codec pins */
-       snd_soc_dapm_disable_pin(codec, "LOUT2");
-       snd_soc_dapm_disable_pin(codec, "ROUT2");
-       snd_soc_dapm_disable_pin(codec, "OUT3");
-       snd_soc_dapm_disable_pin(codec, "OUT4");
-       snd_soc_dapm_disable_pin(codec, "LINE1");
-       snd_soc_dapm_disable_pin(codec, "LINE2");
-
-
-       /* set endpoints to default mode */
-       set_scenario_endpoints(codec, NEO_AUDIO_OFF);
+       snd_soc_dapm_nc_pin(codec, "LOUT2");
+       snd_soc_dapm_nc_pin(codec, "ROUT2");
+       snd_soc_dapm_nc_pin(codec, "OUT3");
+       snd_soc_dapm_nc_pin(codec, "OUT4");
+       snd_soc_dapm_nc_pin(codec, "LINE1");
+       snd_soc_dapm_nc_pin(codec, "LINE2");
 
        /* Add neo1973 specific widgets */
        snd_soc_dapm_new_controls(codec, wm8753_dapm_widgets,
                                  ARRAY_SIZE(wm8753_dapm_widgets));
 
+       /* set endpoints to default mode */
+       set_scenario_endpoints(codec, NEO_AUDIO_OFF);
+
        /* add neo1973 specific controls */
        for (i = 0; i < ARRAY_SIZE(wm8753_neo1973_controls); i++) {
                err = snd_ctl_add(codec->card,
@@ -603,6 +602,8 @@ static int lm4857_i2c_probe(struct i2c_client *client,
 {
        DBG("Entered %s\n", __func__);
 
+       i2c = client;
+
        lm4857_write_regs();
        return 0;
 }
@@ -611,6 +612,8 @@ static int lm4857_i2c_remove(struct i2c_client *client)
 {
        DBG("Entered %s\n", __func__);
 
+       i2c = NULL;
+
        return 0;
 }
 
@@ -650,7 +653,7 @@ static void lm4857_shutdown(struct i2c_client *dev)
 }
 
 static const struct i2c_device_id lm4857_i2c_id[] = {
-       { "neo1973_lm4857", 0 }
+       { "neo1973_lm4857", 0 },
        { }
 };
 
@@ -668,48 +671,6 @@ static struct i2c_driver lm4857_i2c_driver = {
 };
 
 static struct platform_device *neo1973_snd_device;
-static struct i2c_client *lm4857_client;
-
-static int __init neo1973_add_lm4857_device(struct platform_device *pdev,
-                                           int i2c_bus,
-                                           unsigned short i2c_address)
-{
-       struct i2c_board_info info;
-       struct i2c_adapter *adapter;
-       struct i2c_client *client;
-       int ret;
-
-       ret = i2c_add_driver(&lm4857_i2c_driver);
-       if (ret != 0) {
-               dev_err(&pdev->dev, "can't add lm4857 driver\n");
-               return ret;
-       }
-
-       memset(&info, 0, sizeof(struct i2c_board_info));
-       info.addr = i2c_address;
-       strlcpy(info.type, "neo1973_lm4857", I2C_NAME_SIZE);
-
-       adapter = i2c_get_adapter(i2c_bus);
-       if (!adapter) {
-               dev_err(&pdev->dev, "can't get i2c adapter %d\n", i2c_bus);
-               goto err_driver;
-       }
-
-       client = i2c_new_device(adapter, &info);
-       i2c_put_adapter(adapter);
-       if (!client) {
-               dev_err(&pdev->dev, "can't add lm4857 device at 0x%x\n",
-                       (unsigned int)info.addr);
-               goto err_driver;
-       }
-
-       lm4857_client = client;
-       return 0;
-
-err_driver:
-       i2c_del_driver(&lm4857_i2c_driver);
-       return -ENODEV;
-}
 
 static int __init neo1973_init(void)
 {
@@ -736,8 +697,8 @@ static int __init neo1973_init(void)
                return ret;
        }
 
-       ret = neo1973_add_lm4857_device(neo1973_snd_device,
-                                       neo1973_wm8753_setup, 0x7C);
+       ret = i2c_add_driver(&lm4857_i2c_driver);
+
        if (ret != 0)
                platform_device_unregister(neo1973_snd_device);
 
@@ -748,7 +709,6 @@ static void __exit neo1973_exit(void)
 {
        DBG("Entered %s\n", __func__);
 
-       i2c_unregister_device(lm4857_client);
        i2c_del_driver(&lm4857_i2c_driver);
        platform_device_unregister(neo1973_snd_device);
 }
index ad381138fc2e482e0bf0110a96cf32c385ba8c04..462e635dfc74bc084f2c140480c4e6fe8e8cd7cc 100644 (file)
@@ -4,8 +4,7 @@
  * Copyright 2005 Wolfson Microelectronics PLC.
  * Copyright 2005 Openedhand Ltd.
  *
- * Author: Liam Girdwood
- *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
  *         with code, comments and ideas from :-
  *         Richard Purdie <richard@openedhand.com>
  *
@@ -1886,7 +1885,7 @@ module_init(snd_soc_init);
 module_exit(snd_soc_exit);
 
 /* Module information */
-MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com");
+MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk");
 MODULE_DESCRIPTION("ALSA SoC Core");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:soc-audio");
index 9ca9c08610fa85bfd7fa7967555f07e1c6ac8082..efbd0b37810aba581672c1208bf82a99a2d1554a 100644 (file)
@@ -2,8 +2,7 @@
  * soc-dapm.c  --  ALSA SoC Dynamic Audio Power Management
  *
  * Copyright 2005 Wolfson Microelectronics PLC.
- * Author: Liam Girdwood
- *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
  *
  *  This program is free software; you can redistribute  it and/or modify it
  *  under  the terms of  the GNU General  Public License as published by the
@@ -1483,6 +1482,26 @@ int snd_soc_dapm_disable_pin(struct snd_soc_codec *codec, char *pin)
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin);
 
+/**
+ * snd_soc_dapm_nc_pin - permanently disable pin.
+ * @codec: SoC codec
+ * @pin: pin name
+ *
+ * Marks the specified pin as being not connected, disabling it along
+ * any parent or child widgets.  At present this is identical to
+ * snd_soc_dapm_disable_pin() but in future it will be extended to do
+ * additional things such as disabling controls which only affect
+ * paths through the pin.
+ *
+ * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
+ * do any widget power switching.
+ */
+int snd_soc_dapm_nc_pin(struct snd_soc_codec *codec, char *pin)
+{
+       return snd_soc_dapm_set_pin(codec, pin, 0);
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin);
+
 /**
  * snd_soc_dapm_get_pin_status - get audio pin status
  * @codec: audio codec
@@ -1521,6 +1540,6 @@ void snd_soc_dapm_free(struct snd_soc_device *socdev)
 EXPORT_SYMBOL_GPL(snd_soc_dapm_free);
 
 /* Module information */
-MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com");
+MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk");
 MODULE_DESCRIPTION("Dynamic Audio Power Management core for ALSA SoC");
 MODULE_LICENSE("GPL");