From 80736279957aa9dfe16ff3cc6e2695dcbf1f5436 Mon Sep 17 00:00:00 2001 From: Robert Reif Date: Sun, 12 Oct 2008 20:52:26 -0700 Subject: [PATCH] --- yaml --- r: 113715 b: refs/heads/master c: 4245e59d1239a5270670807b114856365a863df8 h: refs/heads/master i: 113713: e8034f06d69227502e63446a9dffd2795899b2ef 113711: c627db8f0eb9b8a78da8875ac6fc0a6d60737c5a v: v3 --- [refs] | 2 +- trunk/Documentation/00-INDEX | 2 + .../feature-removal-schedule.txt | 8 + trunk/Documentation/filesystems/proc.txt | 7 + trunk/Documentation/{timers => }/hpet.txt | 43 +- trunk/Documentation/timers/00-INDEX | 10 - trunk/MAINTAINERS | 18 +- trunk/arch/Kconfig | 14 - trunk/arch/alpha/Kconfig | 4 +- trunk/arch/alpha/include/asm/statfs.h | 4 - trunk/arch/arm/Kconfig | 4 +- trunk/arch/arm/include/asm/statfs.h | 34 +- trunk/arch/arm/kernel/dma.c | 17 + trunk/arch/avr32/include/asm/a.out.h | 20 + trunk/arch/blackfin/include/asm/a.out.h | 19 + trunk/arch/blackfin/kernel/bfin_dma_5xx.c | 13 +- .../mach-bf527/include/mach/bfin_serial_5xx.h | 6 +- .../mach-bf533/include/mach/bfin_serial_5xx.h | 4 +- .../mach-bf537/include/mach/bfin_serial_5xx.h | 6 +- .../mach-bf548/include/mach/bfin_serial_5xx.h | 6 +- .../mach-bf561/include/mach/bfin_serial_5xx.h | 4 +- trunk/arch/cris/arch-v10/boot/tools/build.c | 1 + trunk/arch/h8300/Kconfig | 3 + trunk/arch/h8300/include/asm/a.out.h | 20 + trunk/arch/h8300/kernel/process.c | 1 + trunk/arch/ia64/include/asm/a.out.h | 32 + trunk/arch/ia64/include/asm/statfs.h | 52 +- trunk/arch/ia64/mm/init.c | 1 + trunk/arch/m32r/Kconfig | 3 + trunk/arch/m68k/Kconfig | 4 +- trunk/arch/m68knommu/Kconfig | 3 + trunk/arch/m68knommu/include/asm/a.out.h | 1 + trunk/arch/m68knommu/kernel/process.c | 1 + trunk/arch/m68knommu/kernel/traps.c | 1 + trunk/arch/mips/include/asm/a.out.h | 35 + trunk/arch/mips/kernel/process.c | 1 + trunk/arch/mips/kernel/syscall.c | 1 + trunk/arch/mn10300/Kconfig | 3 + trunk/arch/parisc/Kconfig | 3 + trunk/arch/powerpc/include/asm/a.out.h | 20 + trunk/arch/powerpc/include/asm/statfs.h | 54 + trunk/arch/powerpc/kernel/softemu8xx.c | 1 + trunk/arch/powerpc/kernel/traps.c | 1 + trunk/arch/powerpc/platforms/chrp/setup.c | 1 + trunk/arch/powerpc/platforms/maple/setup.c | 1 + trunk/arch/powerpc/platforms/powermac/setup.c | 1 + trunk/arch/powerpc/platforms/pseries/setup.c | 1 + trunk/arch/s390/include/asm/statfs.h | 11 +- trunk/arch/sparc/include/asm/Kbuild | 2 + trunk/arch/sparc/include/asm/serial.h | 6 - trunk/arch/sparc/include/asm/statfs.h | 8 +- trunk/arch/sparc/include/asm/statfs_32.h | 6 + trunk/arch/sparc/include/asm/statfs_64.h | 54 + trunk/arch/sparc/kernel/sun4d_smp.c | 1 + trunk/arch/sparc/kernel/sun4m_smp.c | 1 + trunk/arch/um/Kconfig.i386 | 8 +- trunk/arch/um/Kconfig.x86_64 | 3 + trunk/arch/um/drivers/line.c | 2 - trunk/arch/x86/Kconfig | 6 +- trunk/arch/x86/Kconfig.cpu | 29 +- trunk/arch/x86/Makefile_32.cpu | 1 + trunk/arch/x86/configs/i386_defconfig | 1 + trunk/arch/x86/configs/x86_64_defconfig | 1 + trunk/arch/x86/ia32/ia32entry.S | 26 +- trunk/arch/x86/kernel/Makefile | 2 +- trunk/arch/x86/kernel/alternative.c | 2 +- trunk/arch/x86/kernel/apic_32.c | 4 - trunk/arch/x86/kernel/apic_64.c | 4 - trunk/arch/x86/kernel/cpu/common.c | 45 +- trunk/arch/x86/kernel/doublefault_32.c | 2 +- trunk/arch/x86/kernel/dumpstack_32.c | 447 ---- trunk/arch/x86/kernel/dumpstack_64.c | 573 ----- trunk/arch/x86/kernel/entry_32.S | 22 +- trunk/arch/x86/kernel/entry_64.S | 15 +- trunk/arch/x86/kernel/es7000_32.c | 28 +- trunk/arch/x86/kernel/genx2apic_uv_x.c | 23 +- trunk/arch/x86/kernel/head.c | 1 - trunk/arch/x86/kernel/hpet.c | 6 +- trunk/arch/x86/kernel/irqinit_64.c | 43 +- trunk/arch/x86/kernel/process_32.c | 4 +- trunk/arch/x86/kernel/process_64.c | 7 +- trunk/arch/x86/kernel/quirks.c | 41 +- trunk/arch/x86/kernel/setup.c | 10 +- trunk/arch/x86/kernel/smpboot.c | 87 +- trunk/arch/x86/kernel/time_32.c | 7 +- trunk/arch/x86/kernel/time_64.c | 23 +- trunk/arch/x86/kernel/{traps.c => traps_32.c} | 893 +++++--- trunk/arch/x86/kernel/traps_64.c | 1214 ++++++++++ trunk/arch/x86/mach-generic/es7000.c | 20 +- trunk/arch/x86/mm/Makefile | 6 +- .../arch/x86/mm/{numa_32.c => discontig_32.c} | 0 trunk/arch/x86/mm/fault.c | 5 + trunk/arch/x86/mm/gup.c | 10 +- trunk/arch/x86/mm/init_32.c | 2 +- trunk/arch/x86/mm/init_64.c | 9 +- trunk/arch/x86/mm/ioremap.c | 143 +- trunk/arch/x86/mm/srat_64.c | 2 +- trunk/arch/x86/oprofile/Makefile | 2 +- trunk/arch/x86/oprofile/nmi_int.c | 27 +- trunk/arch/x86/oprofile/op_model_amd.c | 543 ----- trunk/arch/x86/oprofile/op_model_athlon.c | 190 ++ trunk/arch/x86/oprofile/op_x86_model.h | 4 +- trunk/arch/x86/pci/fixup.c | 28 - trunk/drivers/bluetooth/hci_ldisc.c | 2 +- trunk/drivers/char/Kconfig | 4 +- trunk/drivers/char/Makefile | 2 +- trunk/drivers/char/amiserial.c | 6 + trunk/drivers/char/applicom.c | 6 +- trunk/drivers/char/cyclades.c | 21 +- trunk/drivers/char/epca.c | 5 +- trunk/drivers/char/generic_serial.c | 21 + trunk/drivers/char/hpet.c | 159 +- trunk/drivers/char/hvc_console.c | 4 +- trunk/drivers/char/ip2/Makefile | 2 +- trunk/drivers/char/ip2/i2ellis.c | 32 + trunk/drivers/char/ip2/i2ellis.h | 2 + trunk/drivers/char/ip2/ip2base.c | 108 + trunk/drivers/char/ip2/ip2main.c | 550 +++-- trunk/drivers/char/isicom.c | 61 +- trunk/drivers/char/istallion.c | 113 +- trunk/drivers/char/moxa.c | 61 +- trunk/drivers/char/mxser.c | 193 +- trunk/drivers/char/n_hdlc.c | 2 +- trunk/drivers/char/n_r3964.c | 8 +- trunk/drivers/char/n_tty.c | 125 +- trunk/drivers/char/nozomi.c | 5 +- trunk/drivers/char/pcmcia/ipwireless/tty.c | 19 +- trunk/drivers/char/pty.c | 335 +-- trunk/drivers/char/stallion.c | 139 +- trunk/drivers/char/sx.c | 4 +- trunk/drivers/char/tpm/tpm.c | 96 +- trunk/drivers/char/tpm/tpm.h | 3 +- trunk/drivers/char/tpm/tpm_tis.c | 14 +- trunk/drivers/char/tty_audit.c | 2 +- trunk/drivers/char/tty_buffer.c | 511 ----- trunk/drivers/char/tty_io.c | 1382 ++++++++---- trunk/drivers/char/tty_ioctl.c | 212 +- trunk/drivers/char/tty_port.c | 96 - trunk/drivers/char/vt.c | 84 +- trunk/drivers/char/vt_ioctl.c | 2 - trunk/drivers/isdn/capi/capi.c | 2 +- trunk/drivers/isdn/gigaset/ser-gigaset.c | 27 +- trunk/drivers/media/video/cafe_ccic.c | 13 +- trunk/drivers/mmc/host/sdhci-pci.c | 2 +- trunk/drivers/mtd/nand/cafe_nand.c | 6 +- trunk/drivers/net/wan/Kconfig | 2 +- trunk/drivers/oprofile/buffer_sync.c | 209 +- trunk/drivers/oprofile/cpu_buffer.c | 74 +- trunk/drivers/oprofile/cpu_buffer.h | 2 - trunk/drivers/s390/char/fs3270.c | 17 +- trunk/drivers/serial/8250.c | 52 +- trunk/drivers/serial/8250_pci.c | 4 +- trunk/drivers/serial/Kconfig | 17 +- trunk/drivers/serial/Makefile | 16 +- trunk/drivers/serial/bfin_5xx.c | 123 +- trunk/drivers/serial/crisv10.c | 5 +- trunk/drivers/serial/mcfserial.c | 1965 +++++++++++++++++ trunk/drivers/serial/mcfserial.h | 74 + trunk/drivers/serial/serial_core.c | 12 +- trunk/drivers/usb/serial/aircable.c | 15 +- trunk/drivers/usb/serial/belkin_sa.c | 3 +- trunk/drivers/usb/serial/console.c | 8 +- trunk/drivers/usb/serial/cyberjack.c | 3 +- trunk/drivers/usb/serial/cypress_m8.c | 5 +- trunk/drivers/usb/serial/digi_acceleport.c | 19 +- trunk/drivers/usb/serial/empeg.c | 8 +- trunk/drivers/usb/serial/ftdi_sio.c | 25 +- trunk/drivers/usb/serial/garmin_gps.c | 3 +- trunk/drivers/usb/serial/generic.c | 3 +- trunk/drivers/usb/serial/io_edgeport.c | 43 +- trunk/drivers/usb/serial/io_ti.c | 26 +- trunk/drivers/usb/serial/ipaq.c | 3 +- trunk/drivers/usb/serial/ipw.c | 3 +- trunk/drivers/usb/serial/ir-usb.c | 3 +- trunk/drivers/usb/serial/iuu_phoenix.c | 3 +- trunk/drivers/usb/serial/keyspan.c | 77 +- trunk/drivers/usb/serial/keyspan_pda.c | 16 +- trunk/drivers/usb/serial/kl5kusb105.c | 3 +- trunk/drivers/usb/serial/kobil_sct.c | 3 +- trunk/drivers/usb/serial/mct_u232.c | 6 +- trunk/drivers/usb/serial/mos7720.c | 36 +- trunk/drivers/usb/serial/mos7840.c | 7 +- trunk/drivers/usb/serial/navman.c | 3 +- trunk/drivers/usb/serial/omninet.c | 10 +- trunk/drivers/usb/serial/option.c | 18 +- trunk/drivers/usb/serial/oti6858.c | 7 +- trunk/drivers/usb/serial/pl2303.c | 15 +- trunk/drivers/usb/serial/safe_serial.c | 11 +- trunk/drivers/usb/serial/sierra.c | 16 +- trunk/drivers/usb/serial/spcp8x5.c | 3 +- trunk/drivers/usb/serial/ti_usb_3410_5052.c | 44 +- trunk/drivers/usb/serial/usb-serial.c | 24 +- trunk/drivers/usb/serial/visor.c | 18 +- trunk/drivers/usb/serial/whiteheat.c | 8 +- trunk/drivers/video/backlight/mbp_nvidia_bl.c | 4 +- trunk/fs/Kconfig.binfmt | 6 +- trunk/fs/debugfs/inode.c | 3 +- trunk/fs/devpts/inode.c | 66 +- trunk/fs/dquot.c | 6 +- trunk/fs/efs/super.c | 2 + trunk/fs/open.c | 3 +- trunk/fs/proc/Kconfig | 10 - trunk/fs/proc/array.c | 7 + trunk/fs/proc/base.c | 21 +- trunk/fs/proc/inode.c | 2 +- trunk/fs/proc/internal.h | 2 + trunk/fs/proc/proc_misc.c | 1 + trunk/fs/proc/proc_sysctl.c | 6 +- trunk/fs/proc/task_mmu.c | 16 +- trunk/fs/proc/task_nommu.c | 5 + trunk/fs/proc/vmcore.c | 6 + trunk/include/asm-cris/a.out.h | 26 + trunk/include/asm-generic/statfs.h | 65 +- trunk/include/asm-m32r/a.out.h | 20 + trunk/include/asm-parisc/a.out.h | 20 + trunk/include/asm-parisc/statfs.h | 55 +- trunk/include/asm-x86/desc.h | 14 +- trunk/include/asm-x86/es7000/mpparse.h | 1 - trunk/include/asm-x86/fixmap_32.h | 4 +- trunk/include/asm-x86/fixmap_64.h | 12 +- trunk/include/asm-x86/io.h | 15 +- trunk/include/asm-x86/io_64.h | 3 + trunk/include/asm-x86/ioctls.h | 6 - trunk/include/asm-x86/irqflags.h | 21 + trunk/include/asm-x86/kdebug.h | 3 +- trunk/include/asm-x86/kprobes.h | 9 + .../include/asm-x86/mach-default/mach_traps.h | 6 + trunk/include/asm-x86/module.h | 2 + trunk/include/asm-x86/nmi.h | 4 + trunk/include/asm-x86/page.h | 8 +- trunk/include/asm-x86/page_32.h | 10 +- trunk/include/asm-x86/pgtable.h | 16 +- trunk/include/asm-x86/ptrace.h | 4 + trunk/include/asm-x86/segment.h | 6 + trunk/include/asm-x86/smp.h | 8 +- trunk/include/asm-x86/statfs.h | 61 +- trunk/include/asm-x86/system.h | 5 +- trunk/include/asm-x86/traps.h | 73 +- trunk/include/asm-xtensa/a.out.h | 29 + trunk/include/linux/devpts_fs.h | 31 +- trunk/include/linux/dmi.h | 41 +- trunk/include/linux/hpet.h | 14 +- trunk/include/linux/magic.h | 4 - trunk/include/linux/mod_devicetable.h | 47 - trunk/include/linux/oprofile.h | 2 - trunk/include/linux/pci_ids.h | 4 +- trunk/include/linux/serial.h | 16 - trunk/include/linux/serial_core.h | 2 +- trunk/include/linux/termios.h | 15 - trunk/include/linux/tty.h | 45 +- trunk/include/linux/tty_driver.h | 56 +- trunk/include/linux/vt_kern.h | 2 +- trunk/include/net/cipso_ipv4.h | 55 +- trunk/include/net/netlabel.h | 51 +- trunk/include/sound/soc-dapm.h | 1 - trunk/init/Kconfig | 10 + trunk/kernel/acct.c | 2 +- trunk/kernel/auditsc.c | 9 +- trunk/kernel/fork.c | 5 +- trunk/kernel/printk.c | 16 + trunk/kernel/sched_debug.c | 2 + trunk/kernel/sys.c | 4 +- trunk/kernel/sysctl.c | 11 + trunk/mm/shmem.c | 4 +- trunk/net/ipv4/cipso_ipv4.c | 656 ++---- trunk/net/ipv4/ip_options.c | 2 +- trunk/net/netlabel/Makefile | 3 +- trunk/net/netlabel/netlabel_addrlist.c | 388 ---- trunk/net/netlabel/netlabel_addrlist.h | 189 -- trunk/net/netlabel/netlabel_cipso_v4.c | 136 +- trunk/net/netlabel/netlabel_cipso_v4.h | 10 +- trunk/net/netlabel/netlabel_domainhash.c | 393 +--- trunk/net/netlabel/netlabel_domainhash.h | 40 +- trunk/net/netlabel/netlabel_kapi.c | 272 +-- trunk/net/netlabel/netlabel_mgmt.c | 410 +--- trunk/net/netlabel/netlabel_mgmt.h | 59 +- trunk/net/netlabel/netlabel_unlabeled.c | 456 ++-- trunk/scripts/mod/file2alias.c | 57 - trunk/security/inode.c | 3 +- trunk/security/selinux/hooks.c | 232 +- trunk/security/selinux/include/netlabel.h | 44 +- trunk/security/selinux/include/objsec.h | 9 +- trunk/security/selinux/netlabel.c | 280 +-- trunk/security/selinux/ss/services.c | 13 +- trunk/security/smack/smack_lsm.c | 5 +- trunk/security/smack/smackfs.c | 4 +- trunk/sound/oss/ac97_codec.c | 2 +- trunk/sound/pci/ac97/ac97_patch.c | 2 +- trunk/sound/pci/hda/patch_sigmatel.c | 50 +- trunk/sound/soc/at91/Kconfig | 17 + trunk/sound/soc/at91/Makefile | 5 + trunk/sound/soc/at91/at91-ssc.c | 2 +- trunk/sound/soc/at91/eti_b1_wm8731.c | 349 +++ trunk/sound/soc/blackfin/Kconfig | 16 - trunk/sound/soc/blackfin/Makefile | 3 +- trunk/sound/soc/blackfin/bf5xx-ac97-pcm.c | 42 +- trunk/sound/soc/blackfin/bf5xx-ac97.c | 1 + trunk/sound/soc/blackfin/bf5xx-ad73311.c | 240 -- trunk/sound/soc/blackfin/bf5xx-i2s.c | 47 +- trunk/sound/soc/blackfin/bf5xx-sport.h | 2 - trunk/sound/soc/codecs/Kconfig | 11 +- trunk/sound/soc/codecs/Makefile | 4 - trunk/sound/soc/codecs/ac97.c | 3 +- trunk/sound/soc/codecs/ad1980.c | 1 + trunk/sound/soc/codecs/ad73311.c | 107 - trunk/sound/soc/codecs/ad73311.h | 90 - trunk/sound/soc/codecs/ak4535.c | 1 + trunk/sound/soc/codecs/ssm2602.c | 1 + trunk/sound/soc/codecs/tlv320aic23.c | 714 ------ trunk/sound/soc/codecs/tlv320aic23.h | 122 - trunk/sound/soc/codecs/tlv320aic3x.c | 5 +- trunk/sound/soc/codecs/uda1380.c | 1 + trunk/sound/soc/codecs/wm8510.c | 111 +- trunk/sound/soc/codecs/wm8510.h | 1 - trunk/sound/soc/codecs/wm8580.c | 2 + trunk/sound/soc/codecs/wm8731.c | 1 + trunk/sound/soc/codecs/wm8750.c | 1 + trunk/sound/soc/codecs/wm8753.c | 75 +- trunk/sound/soc/codecs/wm8753.h | 4 +- trunk/sound/soc/codecs/wm8900.c | 1 + trunk/sound/soc/codecs/wm8903.c | 4 +- trunk/sound/soc/codecs/wm8971.c | 1 + trunk/sound/soc/codecs/wm8990.c | 1 + trunk/sound/soc/codecs/wm9712.c | 3 +- trunk/sound/soc/codecs/wm9713.c | 3 +- trunk/sound/soc/omap/Kconfig | 8 - trunk/sound/soc/omap/Makefile | 2 - trunk/sound/soc/omap/n810.c | 6 +- trunk/sound/soc/omap/omap-mcbsp.c | 181 +- trunk/sound/soc/omap/omap-mcbsp.h | 16 +- trunk/sound/soc/omap/omap-pcm.c | 4 +- trunk/sound/soc/omap/osk5912.c | 232 -- trunk/sound/soc/pxa/corgi.c | 6 +- trunk/sound/soc/pxa/em-x270.c | 2 +- trunk/sound/soc/pxa/poodle.c | 6 +- trunk/sound/soc/pxa/pxa2xx-i2s.c | 4 +- trunk/sound/soc/pxa/spitz.c | 16 +- trunk/sound/soc/pxa/tosa.c | 6 +- trunk/sound/soc/s3c24xx/neo1973_wm8753.c | 72 +- trunk/sound/soc/soc-core.c | 5 +- trunk/sound/soc/soc-dapm.c | 25 +- 341 files changed, 9334 insertions(+), 10747 deletions(-) rename trunk/Documentation/{timers => }/hpet.txt (81%) delete mode 100644 trunk/Documentation/timers/00-INDEX create mode 100644 trunk/arch/avr32/include/asm/a.out.h create mode 100644 trunk/arch/blackfin/include/asm/a.out.h create mode 100644 trunk/arch/h8300/include/asm/a.out.h create mode 100644 trunk/arch/ia64/include/asm/a.out.h create mode 100644 trunk/arch/m68knommu/include/asm/a.out.h create mode 100644 trunk/arch/mips/include/asm/a.out.h create mode 100644 trunk/arch/powerpc/include/asm/a.out.h delete mode 100644 trunk/arch/sparc/include/asm/serial.h create mode 100644 trunk/arch/sparc/include/asm/statfs_32.h create mode 100644 trunk/arch/sparc/include/asm/statfs_64.h delete mode 100644 trunk/arch/x86/kernel/dumpstack_32.c delete mode 100644 trunk/arch/x86/kernel/dumpstack_64.c rename trunk/arch/x86/kernel/{traps.c => traps_32.c} (57%) create mode 100644 trunk/arch/x86/kernel/traps_64.c rename trunk/arch/x86/mm/{numa_32.c => discontig_32.c} (100%) delete mode 100644 trunk/arch/x86/oprofile/op_model_amd.c create mode 100644 trunk/arch/x86/oprofile/op_model_athlon.c create mode 100644 trunk/drivers/char/ip2/ip2base.c delete mode 100644 trunk/drivers/char/tty_buffer.c delete mode 100644 trunk/drivers/char/tty_port.c create mode 100644 trunk/drivers/serial/mcfserial.c create mode 100644 trunk/drivers/serial/mcfserial.h create mode 100644 trunk/include/asm-cris/a.out.h create mode 100644 trunk/include/asm-m32r/a.out.h create mode 100644 trunk/include/asm-parisc/a.out.h create mode 100644 trunk/include/asm-xtensa/a.out.h delete mode 100644 trunk/net/netlabel/netlabel_addrlist.c delete mode 100644 trunk/net/netlabel/netlabel_addrlist.h create mode 100644 trunk/sound/soc/at91/eti_b1_wm8731.c delete mode 100644 trunk/sound/soc/blackfin/bf5xx-ad73311.c delete mode 100644 trunk/sound/soc/codecs/ad73311.c delete mode 100644 trunk/sound/soc/codecs/ad73311.h delete mode 100644 trunk/sound/soc/codecs/tlv320aic23.c delete mode 100644 trunk/sound/soc/codecs/tlv320aic23.h delete mode 100644 trunk/sound/soc/omap/osk5912.c diff --git a/[refs] b/[refs] index c67f2259d26f..2b9dc3925863 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: be3bfbba8f7f6c8f32e8444ef895433701a3f801 +refs/heads/master: 4245e59d1239a5270670807b114856365a863df8 diff --git a/trunk/Documentation/00-INDEX b/trunk/Documentation/00-INDEX index 438277800103..73060819ed99 100644 --- a/trunk/Documentation/00-INDEX +++ b/trunk/Documentation/00-INDEX @@ -159,6 +159,8 @@ 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 diff --git a/trunk/Documentation/feature-removal-schedule.txt b/trunk/Documentation/feature-removal-schedule.txt index cc8093c15cf5..3d2d0c29f027 100644 --- a/trunk/Documentation/feature-removal-schedule.txt +++ b/trunk/Documentation/feature-removal-schedule.txt @@ -287,6 +287,14 @@ Who: Glauber Costa --------------------------- +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 + +--------------------------- + What: /sys/o2cb symlink When: January 2010 Why: /sys/fs/o2cb is the proper location for this information - /sys/o2cb diff --git a/trunk/Documentation/filesystems/proc.txt b/trunk/Documentation/filesystems/proc.txt index b488edad743c..d831d24d2a6c 100644 --- a/trunk/Documentation/filesystems/proc.txt +++ b/trunk/Documentation/filesystems/proc.txt @@ -1331,6 +1331,13 @@ 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/trunk/Documentation/timers/hpet.txt b/trunk/Documentation/hpet.txt similarity index 81% rename from trunk/Documentation/timers/hpet.txt rename to trunk/Documentation/hpet.txt index e7c09abcfab4..6ad52d9dad6c 100644 --- a/trunk/Documentation/timers/hpet.txt +++ b/trunk/Documentation/hpet.txt @@ -1,32 +1,21 @@ High Precision Event Timer Driver for Linux -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 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 +. 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/x86/kernel/hpet.c. +arch/i386/kernel/time_hpet.c. -The driver provides a userspace API which resembles the API found in the -RTC driver framework. An example user space program is provided below. +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. #include #include @@ -297,3 +286,15 @@ 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. diff --git a/trunk/Documentation/timers/00-INDEX b/trunk/Documentation/timers/00-INDEX deleted file mode 100644 index 397dc35e1323..000000000000 --- a/trunk/Documentation/timers/00-INDEX +++ /dev/null @@ -1,10 +0,0 @@ -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 diff --git a/trunk/MAINTAINERS b/trunk/MAINTAINERS index 74b808205312..6ba3ee822838 100644 --- a/trunk/MAINTAINERS +++ b/trunk/MAINTAINERS @@ -2797,6 +2797,15 @@ 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 @@ -3161,15 +3170,6 @@ 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 diff --git a/trunk/arch/Kconfig b/trunk/arch/Kconfig index 0267babe5eb9..364c6dadde0a 100644 --- a/trunk/arch/Kconfig +++ b/trunk/arch/Kconfig @@ -13,20 +13,6 @@ 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 diff --git a/trunk/arch/alpha/Kconfig b/trunk/arch/alpha/Kconfig index ee35226c44e9..1bec55d63ef6 100644 --- a/trunk/arch/alpha/Kconfig +++ b/trunk/arch/alpha/Kconfig @@ -5,7 +5,6 @@ config ALPHA bool default y - select HAVE_AOUT select HAVE_IDE select HAVE_OPROFILE help @@ -69,6 +68,9 @@ config AUTO_IRQ_AFFINITY depends on SMP default y +config ARCH_SUPPORTS_AOUT + def_bool y + source "init/Kconfig" diff --git a/trunk/arch/alpha/include/asm/statfs.h b/trunk/arch/alpha/include/asm/statfs.h index de35cd438a10..ad15830baefe 100644 --- a/trunk/arch/alpha/include/asm/statfs.h +++ b/trunk/arch/alpha/include/asm/statfs.h @@ -1,10 +1,6 @@ #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 #endif diff --git a/trunk/arch/arm/Kconfig b/trunk/arch/arm/Kconfig index 4853f9df37bd..efeed65b4a66 100644 --- a/trunk/arch/arm/Kconfig +++ b/trunk/arch/arm/Kconfig @@ -8,7 +8,6 @@ mainmenu "Linux Kernel Configuration" config ARM bool default y - select HAVE_AOUT select HAVE_IDE select RTC_LIB select SYS_SUPPORTS_APM_EMULATION @@ -141,6 +140,9 @@ config GENERIC_CALIBRATE_DELAY bool default y +config ARCH_SUPPORTS_AOUT + def_bool y + config ARCH_MAY_HAVE_PC_FDC bool diff --git a/trunk/arch/arm/include/asm/statfs.h b/trunk/arch/arm/include/asm/statfs.h index 079447c05ba7..a02e6a8c3d70 100644 --- a/trunk/arch/arm/include/asm/statfs.h +++ b/trunk/arch/arm/include/asm/statfs.h @@ -1,12 +1,42 @@ #ifndef _ASMARM_STATFS_H #define _ASMARM_STATFS_H +#ifndef __KERNEL_STRICT_NAMES +# include +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. */ -#define ARCH_PACK_STATFS64 __attribute__((packed,aligned(4))) +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))); -#include #endif diff --git a/trunk/arch/arm/kernel/dma.c b/trunk/arch/arm/kernel/dma.c index d006085ed7e7..ba99a2035523 100644 --- a/trunk/arch/arm/kernel/dma.c +++ b/trunk/arch/arm/kernel/dma.c @@ -25,6 +25,23 @@ 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/trunk/arch/avr32/include/asm/a.out.h b/trunk/arch/avr32/include/asm/a.out.h new file mode 100644 index 000000000000..e46375a34a72 --- /dev/null +++ b/trunk/arch/avr32/include/asm/a.out.h @@ -0,0 +1,20 @@ +#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/trunk/arch/blackfin/include/asm/a.out.h b/trunk/arch/blackfin/include/asm/a.out.h new file mode 100644 index 000000000000..6c3d652ebd33 --- /dev/null +++ b/trunk/arch/blackfin/include/asm/a.out.h @@ -0,0 +1,19 @@ +#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__ */ diff --git a/trunk/arch/blackfin/kernel/bfin_dma_5xx.c b/trunk/arch/blackfin/kernel/bfin_dma_5xx.c index 339293d677cc..93229b3d6e3e 100644 --- a/trunk/arch/blackfin/kernel/bfin_dma_5xx.c +++ b/trunk/arch/blackfin/kernel/bfin_dma_5xx.c @@ -117,14 +117,15 @@ int request_dma(unsigned int channel, char *device_id) #ifdef CONFIG_BF54x if (channel >= CH_UART2_RX && channel <= CH_UART3_TX) { - 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 | + if (strncmp(device_id, "BFIN_UART", 9) == 0) { + dma_ch[channel].regs->peripheral_map &= 0x0FFF; + dma_ch[channel].regs->peripheral_map |= ((channel - CH_UART2_RX + 0xC)<<12); - else - dma_ch[channel].regs->peripheral_map = per_map | + } else { + dma_ch[channel].regs->peripheral_map &= 0x0FFF; + dma_ch[channel].regs->peripheral_map |= ((channel - CH_UART2_RX + 0x6)<<12); + } } #endif diff --git a/trunk/arch/blackfin/mach-bf527/include/mach/bfin_serial_5xx.h b/trunk/arch/blackfin/mach-bf527/include/mach/bfin_serial_5xx.h index 75722d6008b0..2526b6ed6faa 100644 --- a/trunk/arch/blackfin/mach-bf527/include/mach/bfin_serial_5xx.h +++ b/trunk/arch/blackfin/mach-bf527/include/mach/bfin_serial_5xx.h @@ -78,9 +78,6 @@ # define CONFIG_UART1_RTS_PIN -1 # endif #endif - -#define BFIN_UART_TX_FIFO_SIZE 2 - /* * The pin configuration is different from schematic */ @@ -122,6 +119,7 @@ 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; @@ -166,6 +164,8 @@ 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) diff --git a/trunk/arch/blackfin/mach-bf533/include/mach/bfin_serial_5xx.h b/trunk/arch/blackfin/mach-bf533/include/mach/bfin_serial_5xx.h index 815bfe5dd1a9..ebf592b59aab 100644 --- a/trunk/arch/blackfin/mach-bf533/include/mach/bfin_serial_5xx.h +++ b/trunk/arch/blackfin/mach-bf533/include/mach/bfin_serial_5xx.h @@ -69,8 +69,6 @@ # endif #endif -#define BFIN_UART_TX_FIFO_SIZE 2 - struct bfin_serial_port { struct uart_port port; unsigned int old_status; @@ -113,6 +111,7 @@ 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; @@ -143,6 +142,7 @@ 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) { diff --git a/trunk/arch/blackfin/mach-bf537/include/mach/bfin_serial_5xx.h b/trunk/arch/blackfin/mach-bf537/include/mach/bfin_serial_5xx.h index b3f87e1d16a2..1bf56ffa22f9 100644 --- a/trunk/arch/blackfin/mach-bf537/include/mach/bfin_serial_5xx.h +++ b/trunk/arch/blackfin/mach-bf537/include/mach/bfin_serial_5xx.h @@ -78,9 +78,6 @@ # define CONFIG_UART1_RTS_PIN -1 # endif #endif - -#define BFIN_UART_TX_FIFO_SIZE 2 - /* * The pin configuration is different from schematic */ @@ -122,6 +119,7 @@ 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; @@ -166,6 +164,8 @@ 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) diff --git a/trunk/arch/blackfin/mach-bf548/include/mach/bfin_serial_5xx.h b/trunk/arch/blackfin/mach-bf548/include/mach/bfin_serial_5xx.h index e4cf35e7ab9f..5e29446a8e03 100644 --- a/trunk/arch/blackfin/mach-bf548/include/mach/bfin_serial_5xx.h +++ b/trunk/arch/blackfin/mach-bf548/include/mach/bfin_serial_5xx.h @@ -82,9 +82,6 @@ # define CONFIG_UART1_RTS_PIN -1 # endif #endif - -#define BFIN_UART_TX_FIFO_SIZE 2 - /* * The pin configuration is different from schematic */ @@ -108,6 +105,7 @@ 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; @@ -172,6 +170,8 @@ 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) diff --git a/trunk/arch/blackfin/mach-bf561/include/mach/bfin_serial_5xx.h b/trunk/arch/blackfin/mach-bf561/include/mach/bfin_serial_5xx.h index e0ce0c1843d4..8aa02780e642 100644 --- a/trunk/arch/blackfin/mach-bf561/include/mach/bfin_serial_5xx.h +++ b/trunk/arch/blackfin/mach-bf561/include/mach/bfin_serial_5xx.h @@ -69,8 +69,6 @@ # endif #endif -#define BFIN_UART_TX_FIFO_SIZE 2 - struct bfin_serial_port { struct uart_port port; unsigned int old_status; @@ -113,6 +111,7 @@ 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; @@ -143,6 +142,7 @@ 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) { diff --git a/trunk/arch/cris/arch-v10/boot/tools/build.c b/trunk/arch/cris/arch-v10/boot/tools/build.c index c8adef364160..2f9bbb26d603 100644 --- a/trunk/arch/cris/arch-v10/boot/tools/build.c +++ b/trunk/arch/cris/arch-v10/boot/tools/build.c @@ -30,6 +30,7 @@ #include #include /* contains read/write */ #include +#include #include #define MINIX_HEADER 32 diff --git a/trunk/arch/h8300/Kconfig b/trunk/arch/h8300/Kconfig index 107cb5bb9f39..396ab059efa3 100644 --- a/trunk/arch/h8300/Kconfig +++ b/trunk/arch/h8300/Kconfig @@ -66,6 +66,9 @@ config TIME_LOW_RES bool default y +config ARCH_SUPPORTS_AOUT + def_bool y + config NO_IOPORT def_bool y diff --git a/trunk/arch/h8300/include/asm/a.out.h b/trunk/arch/h8300/include/asm/a.out.h new file mode 100644 index 000000000000..ded780f0a492 --- /dev/null +++ b/trunk/arch/h8300/include/asm/a.out.h @@ -0,0 +1,20 @@ +#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__ */ diff --git a/trunk/arch/h8300/kernel/process.c b/trunk/arch/h8300/kernel/process.c index a8ef654a5a0b..dfbe7ab9ffe2 100644 --- a/trunk/arch/h8300/kernel/process.c +++ b/trunk/arch/h8300/kernel/process.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include diff --git a/trunk/arch/ia64/include/asm/a.out.h b/trunk/arch/ia64/include/asm/a.out.h new file mode 100644 index 000000000000..193dcfb67596 --- /dev/null +++ b/trunk/arch/ia64/include/asm/a.out.h @@ -0,0 +1,32 @@ +#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 , Hewlett-Packard Co. + */ + +#include + +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 */ diff --git a/trunk/arch/ia64/include/asm/statfs.h b/trunk/arch/ia64/include/asm/statfs.h index 1e589669de56..811097974f31 100644 --- a/trunk/arch/ia64/include/asm/statfs.h +++ b/trunk/arch/ia64/include/asm/statfs.h @@ -8,13 +8,55 @@ * David Mosberger-Tang , Hewlett-Packard Co */ +#ifndef __KERNEL_STRICT_NAMES +# include +typedef __kernel_fsid_t fsid_t; +#endif + /* - * 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. + * This is ugly --- we're already 64-bit, so just duplicate the definitions */ -#define ARCH_PACK_COMPAT_STATFS64 __attribute__((packed,aligned(4))) +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]; +}; -#include +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 /* _ASM_IA64_STATFS_H */ diff --git a/trunk/arch/ia64/mm/init.c b/trunk/arch/ia64/mm/init.c index f482a9098e32..200100ea7610 100644 --- a/trunk/arch/ia64/mm/init.c +++ b/trunk/arch/ia64/mm/init.c @@ -21,6 +21,7 @@ #include #include +#include #include #include #include diff --git a/trunk/arch/m32r/Kconfig b/trunk/arch/m32r/Kconfig index 00289c178f89..f57113f1f892 100644 --- a/trunk/arch/m32r/Kconfig +++ b/trunk/arch/m32r/Kconfig @@ -36,6 +36,9 @@ config NO_IOPORT config NO_DMA def_bool y +config ARCH_SUPPORTS_AOUT + def_bool y + config HZ int default 100 diff --git a/trunk/arch/m68k/Kconfig b/trunk/arch/m68k/Kconfig index 41e5bf02e230..8c5e1de68fcb 100644 --- a/trunk/arch/m68k/Kconfig +++ b/trunk/arch/m68k/Kconfig @@ -5,7 +5,6 @@ config M68K bool default y - select HAVE_AOUT select HAVE_IDE config MMU @@ -54,6 +53,9 @@ config NO_IOPORT config NO_DMA def_bool SUN3 +config ARCH_SUPPORTS_AOUT + def_bool y + config HZ int default 100 diff --git a/trunk/arch/m68knommu/Kconfig b/trunk/arch/m68knommu/Kconfig index 0a8998315e5e..2e7515e8db98 100644 --- a/trunk/arch/m68knommu/Kconfig +++ b/trunk/arch/m68knommu/Kconfig @@ -73,6 +73,9 @@ 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/trunk/arch/m68knommu/include/asm/a.out.h b/trunk/arch/m68knommu/include/asm/a.out.h new file mode 100644 index 000000000000..ce18ef99de04 --- /dev/null +++ b/trunk/arch/m68knommu/include/asm/a.out.h @@ -0,0 +1 @@ +#include diff --git a/trunk/arch/m68knommu/kernel/process.c b/trunk/arch/m68knommu/kernel/process.c index 3f2d7745f31e..47502d5ec19f 100644 --- a/trunk/arch/m68knommu/kernel/process.c +++ b/trunk/arch/m68knommu/kernel/process.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include diff --git a/trunk/arch/m68knommu/kernel/traps.c b/trunk/arch/m68knommu/kernel/traps.c index 5d5d56bcd0ef..46f8f9d0c408 100644 --- a/trunk/arch/m68knommu/kernel/traps.c +++ b/trunk/arch/m68knommu/kernel/traps.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include diff --git a/trunk/arch/mips/include/asm/a.out.h b/trunk/arch/mips/include/asm/a.out.h new file mode 100644 index 000000000000..cad8371422ab --- /dev/null +++ b/trunk/arch/mips/include/asm/a.out.h @@ -0,0 +1,35 @@ +/* + * 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 */ diff --git a/trunk/arch/mips/kernel/process.c b/trunk/arch/mips/kernel/process.c index ca2e4026ad20..22fc19bbe87f 100644 --- a/trunk/arch/mips/kernel/process.c +++ b/trunk/arch/mips/kernel/process.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include diff --git a/trunk/arch/mips/kernel/syscall.c b/trunk/arch/mips/kernel/syscall.c index 37970d9b2186..343015a2f418 100644 --- a/trunk/arch/mips/kernel/syscall.c +++ b/trunk/arch/mips/kernel/syscall.c @@ -7,6 +7,7 @@ * Copyright (C) 1999, 2000 Silicon Graphics, Inc. * Copyright (C) 2001 MIPS Technologies, Inc. */ +#include #include #include #include diff --git a/trunk/arch/mn10300/Kconfig b/trunk/arch/mn10300/Kconfig index dd557c9cf001..e856218da90d 100644 --- a/trunk/arch/mn10300/Kconfig +++ b/trunk/arch/mn10300/Kconfig @@ -53,6 +53,9 @@ 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 diff --git a/trunk/arch/parisc/Kconfig b/trunk/arch/parisc/Kconfig index 8313fccced5e..a7d4fd353c2b 100644 --- a/trunk/arch/parisc/Kconfig +++ b/trunk/arch/parisc/Kconfig @@ -76,6 +76,9 @@ 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/trunk/arch/powerpc/include/asm/a.out.h b/trunk/arch/powerpc/include/asm/a.out.h new file mode 100644 index 000000000000..89cead6b176e --- /dev/null +++ b/trunk/arch/powerpc/include/asm/a.out.h @@ -0,0 +1,20 @@ +#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 */ diff --git a/trunk/arch/powerpc/include/asm/statfs.h b/trunk/arch/powerpc/include/asm/statfs.h index 5244834583a4..67024026c10d 100644 --- a/trunk/arch/powerpc/include/asm/statfs.h +++ b/trunk/arch/powerpc/include/asm/statfs.h @@ -1,6 +1,60 @@ #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 +#else + +#ifndef __KERNEL_STRICT_NAMES +#include +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 diff --git a/trunk/arch/powerpc/kernel/softemu8xx.c b/trunk/arch/powerpc/kernel/softemu8xx.c index 23c8c5e7dc4d..c906c4bf6835 100644 --- a/trunk/arch/powerpc/kernel/softemu8xx.c +++ b/trunk/arch/powerpc/kernel/softemu8xx.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include diff --git a/trunk/arch/powerpc/kernel/traps.c b/trunk/arch/powerpc/kernel/traps.c index f5def6cf5cd6..81ccb8dd1a54 100644 --- a/trunk/arch/powerpc/kernel/traps.c +++ b/trunk/arch/powerpc/kernel/traps.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include diff --git a/trunk/arch/powerpc/platforms/chrp/setup.c b/trunk/arch/powerpc/platforms/chrp/setup.c index 272d79a8d289..1ba7ce5aafae 100644 --- a/trunk/arch/powerpc/platforms/chrp/setup.c +++ b/trunk/arch/powerpc/platforms/chrp/setup.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include diff --git a/trunk/arch/powerpc/platforms/maple/setup.c b/trunk/arch/powerpc/platforms/maple/setup.c index d4c61c3c9669..364714757cf1 100644 --- a/trunk/arch/powerpc/platforms/maple/setup.c +++ b/trunk/arch/powerpc/platforms/maple/setup.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include diff --git a/trunk/arch/powerpc/platforms/powermac/setup.c b/trunk/arch/powerpc/platforms/powermac/setup.c index 82c14d203d8b..88ccf3a08a9c 100644 --- a/trunk/arch/powerpc/platforms/powermac/setup.c +++ b/trunk/arch/powerpc/platforms/powermac/setup.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include diff --git a/trunk/arch/powerpc/platforms/pseries/setup.c b/trunk/arch/powerpc/platforms/pseries/setup.c index ec341707e41b..7b01d67b4e48 100644 --- a/trunk/arch/powerpc/platforms/pseries/setup.c +++ b/trunk/arch/powerpc/platforms/pseries/setup.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include diff --git a/trunk/arch/s390/include/asm/statfs.h b/trunk/arch/s390/include/asm/statfs.h index 06cc70307ece..099a45579190 100644 --- a/trunk/arch/s390/include/asm/statfs.h +++ b/trunk/arch/s390/include/asm/statfs.h @@ -12,16 +12,19 @@ #ifndef __s390x__ #include #else -/* - * We can't use because in 64-bit mode - * we mix ints of different sizes in our struct statfs. - */ #ifndef __KERNEL_STRICT_NAMES + #include + 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; diff --git a/trunk/arch/sparc/include/asm/Kbuild b/trunk/arch/sparc/include/asm/Kbuild index 2d2769d766ec..2ba7183bc1f0 100644 --- a/trunk/arch/sparc/include/asm/Kbuild +++ b/trunk/arch/sparc/include/asm/Kbuild @@ -15,6 +15,8 @@ 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/trunk/arch/sparc/include/asm/serial.h b/trunk/arch/sparc/include/asm/serial.h deleted file mode 100644 index f90d61c28059..000000000000 --- a/trunk/arch/sparc/include/asm/serial.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef __SPARC_SERIAL_H -#define __SPARC_SERIAL_H - -#define BASE_BAUD ( 1843200 / 16 ) - -#endif /* __SPARC_SERIAL_H */ diff --git a/trunk/arch/sparc/include/asm/statfs.h b/trunk/arch/sparc/include/asm/statfs.h index 55e607ad461d..5e937a73743d 100644 --- a/trunk/arch/sparc/include/asm/statfs.h +++ b/trunk/arch/sparc/include/asm/statfs.h @@ -1,6 +1,8 @@ #ifndef ___ASM_SPARC_STATFS_H #define ___ASM_SPARC_STATFS_H - -#include - +#if defined(__sparc__) && defined(__arch64__) +#include +#else +#include +#endif #endif diff --git a/trunk/arch/sparc/include/asm/statfs_32.h b/trunk/arch/sparc/include/asm/statfs_32.h new file mode 100644 index 000000000000..304520fa8863 --- /dev/null +++ b/trunk/arch/sparc/include/asm/statfs_32.h @@ -0,0 +1,6 @@ +#ifndef _SPARC_STATFS_H +#define _SPARC_STATFS_H + +#include + +#endif diff --git a/trunk/arch/sparc/include/asm/statfs_64.h b/trunk/arch/sparc/include/asm/statfs_64.h new file mode 100644 index 000000000000..79b3c890a5fa --- /dev/null +++ b/trunk/arch/sparc/include/asm/statfs_64.h @@ -0,0 +1,54 @@ +#ifndef _SPARC64_STATFS_H +#define _SPARC64_STATFS_H + +#ifndef __KERNEL_STRICT_NAMES + +#include + +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 diff --git a/trunk/arch/sparc/kernel/sun4d_smp.c b/trunk/arch/sparc/kernel/sun4d_smp.c index ce3d45db94e9..7a6a5e795928 100644 --- a/trunk/arch/sparc/kernel/sun4d_smp.c +++ b/trunk/arch/sparc/kernel/sun4d_smp.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include diff --git a/trunk/arch/sparc/kernel/sun4m_smp.c b/trunk/arch/sparc/kernel/sun4m_smp.c index 0c564ba9e709..5fc386d08c47 100644 --- a/trunk/arch/sparc/kernel/sun4m_smp.c +++ b/trunk/arch/sparc/kernel/sun4m_smp.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include diff --git a/trunk/arch/um/Kconfig.i386 b/trunk/arch/um/Kconfig.i386 index 1f57c113df6d..e09edfa560da 100644 --- a/trunk/arch/um/Kconfig.i386 +++ b/trunk/arch/um/Kconfig.i386 @@ -9,9 +9,8 @@ config UML_X86 default y config X86_32 - bool - default y - select HAVE_AOUT + bool + default y config RWSEM_XCHGADD_ALGORITHM def_bool y @@ -43,3 +42,6 @@ config ARCH_REUSE_HOST_VSYSCALL_AREA config GENERIC_HWEIGHT bool default y + +config ARCH_SUPPORTS_AOUT + def_bool y diff --git a/trunk/arch/um/Kconfig.x86_64 b/trunk/arch/um/Kconfig.x86_64 index 40b3407cfe16..5696e7b374b3 100644 --- a/trunk/arch/um/Kconfig.x86_64 +++ b/trunk/arch/um/Kconfig.x86_64 @@ -37,3 +37,6 @@ config SMP_BROKEN config GENERIC_HWEIGHT bool default y + +config ARCH_SUPPORTS_AOUT + def_bool y diff --git a/trunk/arch/um/drivers/line.c b/trunk/arch/um/drivers/line.c index 14a102e877d6..d741f35d7b3a 100644 --- a/trunk/arch/um/drivers/line.c +++ b/trunk/arch/um/drivers/line.c @@ -275,8 +275,6 @@ 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: diff --git a/trunk/arch/x86/Kconfig b/trunk/arch/x86/Kconfig index f65c2744d573..fc8351f374fd 100644 --- a/trunk/arch/x86/Kconfig +++ b/trunk/arch/x86/Kconfig @@ -18,7 +18,6 @@ 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 @@ -153,6 +152,9 @@ config AUDIT_ARCH bool default X86_64 +config ARCH_SUPPORTS_AOUT + def_bool y + config ARCH_SUPPORTS_OPTIMIZED_INLINING def_bool y @@ -1883,7 +1885,7 @@ config IA32_EMULATION config IA32_AOUT tristate "IA32 a.out support" - depends on IA32_EMULATION + depends on IA32_EMULATION && ARCH_SUPPORTS_AOUT help Support old a.out binaries in the 32bit emulation. diff --git a/trunk/arch/x86/Kconfig.cpu b/trunk/arch/x86/Kconfig.cpu index 0b7c4a3f0651..c5f101360520 100644 --- a/trunk/arch/x86/Kconfig.cpu +++ b/trunk/arch/x86/Kconfig.cpu @@ -38,7 +38,8 @@ config M386 - "Crusoe" for the Transmeta Crusoe series. - "Efficeon" for the Transmeta Efficeon series. - "Winchip-C6" for original IDT Winchip. - - "Winchip-2" for IDT Winchips with 3dNow! capabilities. + - "Winchip-2" for IDT Winchip 2. + - "Winchip-2A" 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. @@ -193,11 +194,19 @@ 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-2/Winchip-2A/Winchip-3" + bool "Winchip-2A/Winchip-3" depends on X86_32 help - Select this for an IDT Winchip-2, 2A or 3. Linux and GCC + Select this for an IDT Winchip-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 @@ -309,7 +318,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 || MWINCHIPC6 || MCRUSOE || MEFFICEON || MCYRIXIII || MK6 || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || M586 || MVIAC3_2 || MGEODE_LX + default "5" if MWINCHIP3D || MWINCHIP2 || 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 @@ -351,7 +360,7 @@ config X86_POPAD_OK config X86_ALIGNMENT_16 def_bool y - depends on MWINCHIP3D || MWINCHIPC6 || MCYRIXIII || X86_ELAN || MK6 || M586MMX || M586TSC || M586 || M486 || MVIAC3_2 || MGEODEGX1 + depends on MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 || MCYRIXIII || X86_ELAN || MK6 || M586MMX || M586TSC || M586 || M486 || MVIAC3_2 || MGEODEGX1 config X86_INTEL_USERCOPY def_bool y @@ -359,7 +368,7 @@ config X86_INTEL_USERCOPY config X86_USE_PPRO_CHECKSUM def_bool y - depends on MWINCHIP3D || MWINCHIPC6 || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MK8 || MVIAC3_2 || MEFFICEON || MGEODE_LX || MCORE2 + depends on MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MK8 || MVIAC3_2 || MEFFICEON || MGEODE_LX || MCORE2 config X86_USE_3DNOW def_bool y @@ -367,7 +376,7 @@ config X86_USE_3DNOW config X86_OOSTORE def_bool y - depends on (MWINCHIP3D || MWINCHIPC6) && MTRR + depends on (MWINCHIP3D || MWINCHIP2 || MWINCHIPC6) && MTRR # # P6_NOPs are a relatively minor optimization that require a family >= @@ -387,7 +396,7 @@ config X86_P6_NOP config X86_TSC def_bool y - 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 + 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 config X86_CMPXCHG64 def_bool y @@ -397,7 +406,7 @@ config X86_CMPXCHG64 # generates cmov. config X86_CMOV def_bool y - depends on (MK8 || MK7 || MCORE2 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MVIAC3_2 || MVIAC7 || MCRUSOE || MEFFICEON || X86_64) + depends on (MK7 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MVIAC3_2 || MVIAC7 || X86_64) config X86_MINIMUM_CPU_FAMILY int @@ -408,7 +417,7 @@ config X86_MINIMUM_CPU_FAMILY config X86_DEBUGCTLMSR def_bool y - depends on !(MK6 || MWINCHIPC6 || MWINCHIP3D || MCYRIXIII || M586MMX || M586TSC || M586 || M486 || M386) + depends on !(MK6 || MWINCHIPC6 || MWINCHIP2 || MWINCHIP3D || MCYRIXIII || M586MMX || M586TSC || M586 || M486 || M386) menuconfig PROCESSOR_SELECT bool "Supported processor vendors" if EMBEDDED diff --git a/trunk/arch/x86/Makefile_32.cpu b/trunk/arch/x86/Makefile_32.cpu index 80177ec052f0..b72b4f753113 100644 --- a/trunk/arch/x86/Makefile_32.cpu +++ b/trunk/arch/x86/Makefile_32.cpu @@ -28,6 +28,7 @@ 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) diff --git a/trunk/arch/x86/configs/i386_defconfig b/trunk/arch/x86/configs/i386_defconfig index 52d0359719d7..ca226ca31288 100644 --- a/trunk/arch/x86/configs/i386_defconfig +++ b/trunk/arch/x86/configs/i386_defconfig @@ -213,6 +213,7 @@ 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 diff --git a/trunk/arch/x86/configs/x86_64_defconfig b/trunk/arch/x86/configs/x86_64_defconfig index f0a03d7a7d63..2c4b1c771e28 100644 --- a/trunk/arch/x86/configs/x86_64_defconfig +++ b/trunk/arch/x86/configs/x86_64_defconfig @@ -210,6 +210,7 @@ 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 diff --git a/trunk/arch/x86/ia32/ia32entry.S b/trunk/arch/x86/ia32/ia32entry.S index eb4314768bf7..ffc1bb4fed7d 100644 --- a/trunk/arch/x86/ia32/ia32entry.S +++ b/trunk/arch/x86/ia32/ia32entry.S @@ -39,11 +39,11 @@ .endm /* clobbers %eax */ - .macro CLEAR_RREGS _r9=rax + .macro CLEAR_RREGS xorl %eax,%eax movq %rax,R11(%rsp) movq %rax,R10(%rsp) - movq %\_r9,R9(%rsp) + movq %rax,R9(%rsp) movq %rax,R8(%rsp) .endm @@ -52,10 +52,11 @@ * 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, _r9=0 - .if \_r9 + .macro LOAD_ARGS32 offset + movl \offset(%rsp),%r11d + movl \offset+8(%rsp),%r10d movl \offset+16(%rsp),%r9d - .endif + movl \offset+24(%rsp),%r8d movl \offset+40(%rsp),%ecx movl \offset+48(%rsp),%edx movl \offset+56(%rsp),%esi @@ -144,7 +145,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),%ebp +1: movl (%rbp),%r9d .section __ex_table,"a" .quad 1b,ia32_badarg .previous @@ -156,7 +157,7 @@ ENTRY(ia32_sysenter_target) cmpl $(IA32_NR_syscalls-1),%eax ja ia32_badsys sysenter_do_call: - IA32_ARG_FIXUP + IA32_ARG_FIXUP 1 sysenter_dispatch: call *ia32_sys_call_table(,%rax,8) movq %rax,RAX-ARGOFFSET(%rsp) @@ -233,17 +234,20 @@ 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 @@ -310,9 +314,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) @@ -353,13 +357,15 @@ cstar_tracesys: #endif xchgl %r9d,%ebp SAVE_REST - CLEAR_RREGS r9 + 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, 1 /* reload args from stack in case ptrace changed it */ + LOAD_ARGS32 ARGOFFSET /* 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 diff --git a/trunk/arch/x86/kernel/Makefile b/trunk/arch/x86/kernel/Makefile index 0d41f0343dc0..5098585f87ce 100644 --- a/trunk/arch/x86/kernel/Makefile +++ b/trunk/arch/x86/kernel/Makefile @@ -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.o irq_$(BITS).o dumpstack_$(BITS).o +obj-y += traps_$(BITS).o irq_$(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 diff --git a/trunk/arch/x86/kernel/alternative.c b/trunk/arch/x86/kernel/alternative.c index a84ac7b570e6..fb04e49776ba 100644 --- a/trunk/arch/x86/kernel/alternative.c +++ b/trunk/arch/x86/kernel/alternative.c @@ -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_present_cpus() == 1 || setup_max_cpus <= 1) + if (num_possible_cpus() == 1 || setup_max_cpus <= 1) alternatives_smp_switch(0); } #endif diff --git a/trunk/arch/x86/kernel/apic_32.c b/trunk/arch/x86/kernel/apic_32.c index 21c831d96af3..a91c57cb666a 100644 --- a/trunk/arch/x86/kernel/apic_32.c +++ b/trunk/arch/x86/kernel/apic_32.c @@ -295,9 +295,6 @@ 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 @@ -322,7 +319,6 @@ 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 diff --git a/trunk/arch/x86/kernel/apic_64.c b/trunk/arch/x86/kernel/apic_64.c index 94ddb69ae15e..53898b65a6ae 100644 --- a/trunk/arch/x86/kernel/apic_64.c +++ b/trunk/arch/x86/kernel/apic_64.c @@ -307,9 +307,6 @@ 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 @@ -334,7 +331,6 @@ 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 diff --git a/trunk/arch/x86/kernel/cpu/common.c b/trunk/arch/x86/kernel/cpu/common.c index 25581dcb280e..fb789dd9e691 100644 --- a/trunk/arch/x86/kernel/cpu/common.c +++ b/trunk/arch/x86/kernel/cpu/common.c @@ -124,25 +124,18 @@ static inline int flag_is_changeable_p(u32 flag) { u32 f1, f2; - /* - * 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)); + 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)); return ((f1^f2) & flag) != 0; } @@ -726,24 +719,12 @@ 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 } @@ -816,7 +797,7 @@ void __cpuinit print_cpu_info(struct cpuinfo_x86 *c) else if (c->cpuid_level >= 0) vendor = c->x86_vendor_id; - if (vendor && !strstr(c->x86_model_id, vendor)) + if (vendor && strncmp(c->x86_model_id, vendor, strlen(vendor))) printk(KERN_CONT "%s ", vendor); if (c->x86_model_id[0]) diff --git a/trunk/arch/x86/kernel/doublefault_32.c b/trunk/arch/x86/kernel/doublefault_32.c index b4f14c6c09d9..395acb12b0d1 100644 --- a/trunk/arch/x86/kernel/doublefault_32.c +++ b/trunk/arch/x86/kernel/doublefault_32.c @@ -66,6 +66,6 @@ struct tss_struct doublefault_tss __cacheline_aligned = { .ds = __USER_DS, .fs = __KERNEL_PERCPU, - .__cr3 = __pa_nodebug(swapper_pg_dir), + .__cr3 = __phys_addr_const((unsigned long)swapper_pg_dir) } }; diff --git a/trunk/arch/x86/kernel/dumpstack_32.c b/trunk/arch/x86/kernel/dumpstack_32.c deleted file mode 100644 index 201ee359a1a9..000000000000 --- a/trunk/arch/x86/kernel/dumpstack_32.c +++ /dev/null @@ -1,447 +0,0 @@ -/* - * Copyright (C) 1991, 1992 Linus Torvalds - * Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#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, ®s->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) (®s->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/trunk/arch/x86/kernel/dumpstack_64.c b/trunk/arch/x86/kernel/dumpstack_64.c deleted file mode 100644 index 086cc8118e39..000000000000 --- a/trunk/arch/x86/kernel/dumpstack_64.c +++ /dev/null @@ -1,573 +0,0 @@ -/* - * Copyright (C) 1991, 1992 Linus Torvalds - * Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#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, ""); - /* - * 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(" "); - } - } 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); diff --git a/trunk/arch/x86/kernel/entry_32.S b/trunk/arch/x86/kernel/entry_32.S index b21fbfaffe39..109792bc7cfa 100644 --- a/trunk/arch/x86/kernel/entry_32.S +++ b/trunk/arch/x86/kernel/entry_32.S @@ -730,7 +730,6 @@ 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 @@ -761,9 +760,20 @@ ENTRY(device_not_available) RING0_INT_FRAME pushl $-1 # mark this as an int CFI_ADJUST_CFA_OFFSET 4 - pushl $do_device_not_available + 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 CFI_ADJUST_CFA_OFFSET 4 - jmp error_code + call math_emulate + addl $4, %esp + CFI_ADJUST_CFA_OFFSET -4 + jmp ret_from_exception CFI_ENDPROC END(device_not_available) @@ -804,7 +814,6 @@ 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 @@ -849,7 +858,6 @@ 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 @@ -890,7 +898,6 @@ 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 @@ -921,7 +928,6 @@ 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 @@ -1024,7 +1030,7 @@ ENTRY(machine_check) RING0_INT_FRAME pushl $0 CFI_ADJUST_CFA_OFFSET 4 - pushl $do_machine_check + pushl machine_check_vector CFI_ADJUST_CFA_OFFSET 4 jmp error_code CFI_ENDPROC diff --git a/trunk/arch/x86/kernel/entry_64.S b/trunk/arch/x86/kernel/entry_64.S index 1db6ce4314e1..cf3a0b2d0059 100644 --- a/trunk/arch/x86/kernel/entry_64.S +++ b/trunk/arch/x86/kernel/entry_64.S @@ -667,13 +667,6 @@ 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 @@ -939,9 +932,6 @@ 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) @@ -1068,8 +1058,7 @@ KPROBE_ENTRY(error_entry) je error_kernelspace error_swapgs: SWAPGS -error_sti: - TRACE_IRQS_OFF +error_sti: movq %rdi,RDI(%rsp) CFI_REL_OFFSET rdi,RDI movq %rsp,%rdi @@ -1243,7 +1232,7 @@ ENTRY(simd_coprocessor_error) END(simd_coprocessor_error) ENTRY(device_not_available) - zeroentry do_device_not_available + zeroentry math_state_restore END(device_not_available) /* runs on exception stack */ diff --git a/trunk/arch/x86/kernel/es7000_32.c b/trunk/arch/x86/kernel/es7000_32.c index f454c78fcef6..849e5cd485b8 100644 --- a/trunk/arch/x86/kernel/es7000_32.c +++ b/trunk/arch/x86/kernel/es7000_32.c @@ -109,7 +109,6 @@ 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 { @@ -244,38 +243,21 @@ parse_unisys_oem (char *oemptr) } #ifdef CONFIG_ACPI -static unsigned long oem_addrX; -static unsigned long oem_size; -int __init find_unisys_acpi_oem_table(unsigned long *oem_addr) +int __init +find_unisys_acpi_oem_table(unsigned long *oem_addr) { struct acpi_table_header *header = NULL; int i = 0; - acpi_size tbl_size; - - while (ACPI_SUCCESS(acpi_get_table_with_size("OEM1", i++, &header, &tbl_size))) { + while (ACPI_SUCCESS(acpi_get_table("OEM1", i++, &header))) { if (!memcmp((char *) &header->oem_id, "UNISYS", 6)) { struct oem_table *t = (struct oem_table *)header; - - 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); + *oem_addr = (unsigned long)__acpi_map_table(t->OEMTableAddr, + t->OEMTableSize); 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 diff --git a/trunk/arch/x86/kernel/genx2apic_uv_x.c b/trunk/arch/x86/kernel/genx2apic_uv_x.c index 33581d94a90e..ae2ffc8a400c 100644 --- a/trunk/arch/x86/kernel/genx2apic_uv_x.c +++ b/trunk/arch/x86/kernel/genx2apic_uv_x.c @@ -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); + apicid = per_cpu(x86_cpu_to_apicid, cpu); /* ZZZ - cache node-local ? */ lapicid = apicid & 0x3f; /* ZZZ macro needed */ pnode = uv_apicid_to_pnode(apicid); val = @@ -202,10 +202,12 @@ 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", @@ -213,15 +215,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, + .vector_allocation_domain = uv_vector_allocation_domain,/* Fixme ZZZ */ .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, - .send_IPI_self = uv_send_IPI_self, + /* ZZZ.send_IPI_self = uv_send_IPI_self, */ .cpu_mask_to_apicid = uv_cpu_mask_to_apicid, - .phys_pkg_id = phys_pkg_id, + .phys_pkg_id = phys_pkg_id, /* Fixme ZZZ */ .get_apic_id = get_apic_id, .set_apic_id = set_apic_id, .apic_id_mask = (0xFFFFFFFFu), @@ -284,13 +286,12 @@ 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, - int max_pnode, enum map_type map_type) +static __init void map_high(char *id, unsigned long base, int shift, enum map_type map_type) { unsigned long bytes, paddr; paddr = base << shift; - bytes = (1UL << shift) * (max_pnode + 1); + bytes = (1UL << shift); printk(KERN_INFO "UV: Map %s_HI 0x%lx - 0x%lx\n", id, paddr, paddr + bytes); if (map_type == map_uc) @@ -306,7 +307,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, max_pnode, map_wb); + map_high("GRU", gru.s.base, shift, map_wb); } static __init void map_config_high(int max_pnode) @@ -316,7 +317,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, max_pnode, map_uc); + map_high("CONFIG", cfg.s.base, shift, map_uc); } static __init void map_mmr_high(int max_pnode) @@ -326,7 +327,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, max_pnode, map_uc); + map_high("MMR", mmr.s.base, shift, map_uc); } static __init void map_mmioh_high(int max_pnode) @@ -336,7 +337,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, max_pnode, map_uc); + map_high("MMIOH", mmioh.s.base, shift, map_uc); } static __init void uv_rtc_init(void) diff --git a/trunk/arch/x86/kernel/head.c b/trunk/arch/x86/kernel/head.c index 1dcb0f13897e..3e66bd364a9d 100644 --- a/trunk/arch/x86/kernel/head.c +++ b/trunk/arch/x86/kernel/head.c @@ -35,7 +35,6 @@ 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. */ diff --git a/trunk/arch/x86/kernel/hpet.c b/trunk/arch/x86/kernel/hpet.c index acf62fc233da..73deaffadd03 100644 --- a/trunk/arch/x86/kernel/hpet.c +++ b/trunk/arch/x86/kernel/hpet.c @@ -115,17 +115,13 @@ 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; diff --git a/trunk/arch/x86/kernel/irqinit_64.c b/trunk/arch/x86/kernel/irqinit_64.c index 5b5be9d43c2a..1f26fd9ec4f4 100644 --- a/trunk/arch/x86/kernel/irqinit_64.c +++ b/trunk/arch/x86/kernel/irqinit_64.c @@ -135,7 +135,7 @@ DEFINE_PER_CPU(vector_irq_t, vector_irq) = { [IRQ15_VECTOR + 1 ... NR_VECTORS - 1] = -1 }; -void __init init_ISA_irqs(void) +static void __init init_ISA_irqs (void) { int i; @@ -164,8 +164,22 @@ void __init init_ISA_irqs(void) void init_IRQ(void) __attribute__((weak, alias("native_init_IRQ"))); -static void __init smp_intr_init(void) +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]); + } + #ifdef CONFIG_SMP /* * The reschedule interrupt is a CPU-to-CPU reschedule-helper @@ -193,12 +207,6 @@ static void __init smp_intr_init(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); @@ -208,25 +216,6 @@ static void __init apic_intr_init(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); diff --git a/trunk/arch/x86/kernel/process_32.c b/trunk/arch/x86/kernel/process_32.c index 0a1302fe6d45..922c14058f97 100644 --- a/trunk/arch/x86/kernel/process_32.c +++ b/trunk/arch/x86/kernel/process_32.c @@ -123,7 +123,7 @@ void cpu_idle(void) } } -void __show_regs(struct pt_regs *regs, int all) +void __show_registers(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_regs(struct pt_regs *regs, int all) void show_regs(struct pt_regs *regs) { - __show_regs(regs, 1); + __show_registers(regs, 1); show_trace(NULL, regs, ®s->sp, regs->bp); } diff --git a/trunk/arch/x86/kernel/process_64.c b/trunk/arch/x86/kernel/process_64.c index cd8c0ed02b7e..ca80394ef5b8 100644 --- a/trunk/arch/x86/kernel/process_64.c +++ b/trunk/arch/x86/kernel/process_64.c @@ -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, int all) +void __show_regs(struct pt_regs *regs) { unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L, fs, gs, shadowgs; unsigned long d0, d1, d2, d3, d6, d7; @@ -175,9 +175,6 @@ void __show_regs(struct pt_regs *regs, int all) rdmsrl(MSR_GS_BASE, gs); rdmsrl(MSR_KERNEL_GS_BASE, shadowgs); - if (!all) - return; - cr0 = read_cr0(); cr2 = read_cr2(); cr3 = read_cr3(); @@ -203,7 +200,7 @@ void __show_regs(struct pt_regs *regs, int all) void show_regs(struct pt_regs *regs) { printk(KERN_INFO "CPU %d:", smp_processor_id()); - __show_regs(regs, 1); + __show_regs(regs); show_trace(NULL, regs, (void *)(regs + 1), regs->bp); } diff --git a/trunk/arch/x86/kernel/quirks.c b/trunk/arch/x86/kernel/quirks.c index f6a11b9b1f98..d13858818100 100644 --- a/trunk/arch/x86/kernel/quirks.c +++ b/trunk/arch/x86/kernel/quirks.c @@ -354,27 +354,9 @@ 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 d, val; - u8 b; + u32 uninitialized_var(val); if (hpet_address || force_hpet_address) return; @@ -384,33 +366,14 @@ 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); diff --git a/trunk/arch/x86/kernel/setup.c b/trunk/arch/x86/kernel/setup.c index 2255782e8d4b..21b8e0a59780 100644 --- a/trunk/arch/x86/kernel/setup.c +++ b/trunk/arch/x86/kernel/setup.c @@ -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_memremap(mapaddr, clen+slop); + p = early_ioremap(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_memremap(pa_data, PAGE_SIZE); + data = early_ioremap(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_memremap(pa_data, sizeof(*data)); + data = early_ioremap(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_memremap(pa_data, sizeof(*data)); + data = early_ioremap(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,8 +998,6 @@ void __init setup_arch(char **cmdline_p) */ acpi_boot_table_init(); - early_acpi_boot_init(); - #ifdef CONFIG_ACPI_NUMA /* * Parse SRAT to discover nodes. diff --git a/trunk/arch/x86/kernel/smpboot.c b/trunk/arch/x86/kernel/smpboot.c index 8c3aca7cb343..76b6f50978f7 100644 --- a/trunk/arch/x86/kernel/smpboot.c +++ b/trunk/arch/x86/kernel/smpboot.c @@ -334,17 +334,14 @@ 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(); + ipi_call_lock_irq(); lock_vector_lock(); __setup_vector_irq(smp_processor_id()); cpu_set(smp_processor_id(), cpu_online_map); unlock_vector_lock(); - ipi_call_unlock(); + ipi_call_unlock_irq(); per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE; - /* enable local interrupts */ - local_irq_enable(); - setup_secondary_clock(); wmb(); @@ -599,12 +596,10 @@ wakeup_secondary_cpu(int logical_apicid, unsigned long start_eip) * Give the other CPU some time to accept the IPI. */ udelay(200); - 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); - } + 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) @@ -1261,6 +1256,39 @@ 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 @@ -1280,13 +1308,21 @@ void __init native_smp_cpus_done(unsigned int max_cpus) */ __init void prefill_possible_map(void) { - int i, possible; + int i; + int possible; /* no processor from mptable or madt */ if (!num_processors) num_processors = 1; - possible = num_processors + disabled_cpus; + if (additional_cpus == -1) { + if (disabled_cpus > 0) + additional_cpus = disabled_cpus; + else + additional_cpus = 0; + } + + possible = num_processors + additional_cpus; if (possible > NR_CPUS) possible = NR_CPUS; @@ -1299,31 +1335,6 @@ __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); diff --git a/trunk/arch/x86/kernel/time_32.c b/trunk/arch/x86/kernel/time_32.c index 77b400f06ea2..bbecf8b6bf96 100644 --- a/trunk/arch/x86/kernel/time_32.c +++ b/trunk/arch/x86/kernel/time_32.c @@ -47,9 +47,10 @@ unsigned long profile_pc(struct pt_regs *regs) unsigned long pc = instruction_pointer(regs); #ifdef CONFIG_SMP - if (!user_mode_vm(regs) && in_lock_functions(pc)) { + if (!v8086_mode(regs) && SEGMENT_IS_KERNEL_CODE(regs->cs) && + in_lock_functions(pc)) { #ifdef CONFIG_FRAME_POINTER - return *(unsigned long *)(regs->bp + sizeof(long)); + return *(unsigned long *)(regs->bp + 4); #else unsigned long *sp = (unsigned long *)®s->sp; @@ -94,7 +95,6 @@ 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,7 +108,6 @@ 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; } diff --git a/trunk/arch/x86/kernel/time_64.c b/trunk/arch/x86/kernel/time_64.c index cb19d650c216..e3d49c553af2 100644 --- a/trunk/arch/x86/kernel/time_64.c +++ b/trunk/arch/x86/kernel/time_64.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include @@ -34,34 +33,23 @@ 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_vm(regs) && in_lock_functions(pc)) { -#ifdef CONFIG_FRAME_POINTER - return *(unsigned long *)(regs->bp + sizeof(long)); -#else + if (!user_mode(regs) && in_lock_functions(pc)) { 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); -irqreturn_t timer_interrupt(int irq, void *dev_id) +static irqreturn_t timer_event_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; } @@ -112,7 +100,7 @@ unsigned long __init calibrate_cpu(void) } static struct irqaction irq0 = { - .handler = timer_interrupt, + .handler = timer_event_interrupt, .flags = IRQF_DISABLED | IRQF_IRQPOLL | IRQF_NOBALANCING, .mask = CPU_MASK_NONE, .name = "timer" @@ -123,13 +111,16 @@ 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(); } diff --git a/trunk/arch/x86/kernel/traps.c b/trunk/arch/x86/kernel/traps_32.c similarity index 57% rename from trunk/arch/x86/kernel/traps.c rename to trunk/arch/x86/kernel/traps_32.c index e062974cce34..0429c5de5ea9 100644 --- a/trunk/arch/x86/kernel/traps.c +++ b/trunk/arch/x86/kernel/traps_32.c @@ -7,11 +7,13 @@ */ /* - * Handle hardware traps and faults. + * 'Traps.c' handles hardware traps and faults after we have saved some + * state in 'asm.s'. */ #include #include #include +#include #include #include #include @@ -30,8 +32,6 @@ #include #include #include -#include -#include #ifdef CONFIG_EISA #include @@ -46,31 +46,21 @@ #include #endif +#include #include #include #include #include #include #include -#include #include #include - -#include - -#ifdef CONFIG_X86_64 -#include -#include -#include -#else -#include -#include #include #include #include #include -#include "cpu/mcheck/mce.h" +#include "mach_traps.h" DECLARE_BITMAP(used_vectors, NR_VECTORS); EXPORT_SYMBOL_GPL(used_vectors); @@ -87,104 +77,418 @@ char ignore_fpu_irq; */ gate_desc idt_table[256] __attribute__((__section__(".data.idt"))) = { { { { 0, 0 } } }, }; -#endif +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; -static inline void conditional_sti(struct pt_regs *regs) +void printk_address(unsigned long address, int reliable) { - if (regs->flags & X86_EFLAGS_IF) - local_irq_enable(); +#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 void preempt_conditional_sti(struct pt_regs *regs) +static inline int valid_stack_ptr(struct thread_info *tinfo, + void *p, unsigned int size) { - inc_preempt_count(); - if (regs->flags & X86_EFLAGS_IF) - local_irq_enable(); + void *t = tinfo; + return p > t && p <= t + THREAD_SIZE - size; } -static inline void preempt_conditional_cli(struct pt_regs *regs) +/* 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) { - if (regs->flags & X86_EFLAGS_IF) - local_irq_disable(); - dec_preempt_count(); + 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; } -#ifdef CONFIG_X86_32 -static inline void -die_if_kernel(const char *str, struct pt_regs *regs, long err) +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 (!user_mode_vm(regs)) - die(str, regs, err); + 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; } /* - * 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. + * Print one address/symbol entries per line. */ -static int lazy_iobitmap_copy(void) +static void print_trace_address(void *data, unsigned long addr, int reliable) { - struct thread_struct *thread; - struct tss_struct *tss; - int cpu; + printk("%s [<%08lx>] ", (char *)data, addr); + if (!reliable) + printk("? "); + print_symbol("%s\n", addr); + touch_nmi_watchdog(); +} - cpu = get_cpu(); - tss = &per_cpu(init_tss, cpu); - thread = ¤t->thread; +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, +}; - 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); +static void +show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, + unsigned long *stack, unsigned long bp, char *log_lvl) +{ + dump_trace(task, regs, stack, bp, &print_trace_ops, log_lvl); + printk("%s =======================\n", 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 % 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); +} + +void show_stack(struct task_struct *task, unsigned long *sp) +{ + printk(" "); + 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("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; + + print_modules(); + __show_registers(regs, 0); + + 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, ®s->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; } - tss->io_bitmap_max = thread->io_bitmap_max; - tss->x86_tss.io_bitmap_base = IO_BITMAP_OFFSET; - tss->io_bitmap_owner = thread; - put_cpu(); + 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"); +} - return 1; +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); } - put_cpu(); + die_nest_count++; + return flags; +} - return 0; +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) (®s->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 inline void +die_if_kernel(const char *str, struct pt_regs *regs, long err) +{ + if (!user_mode_vm(regs)) + die(str, regs, err); +} static void __kprobes -do_trap(int trapnr, int signr, char *str, struct pt_regs *regs, +do_trap(int trapnr, int signr, char *str, int vm86, 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) { - /* - * 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) + if (vm86) 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 @@ -197,18 +501,6 @@ do_trap(int trapnr, int signr, char *str, struct pt_regs *regs, 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 @@ -223,29 +515,29 @@ do_trap(int trapnr, int signr, char *str, struct pt_regs *regs, } 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) \ -dotraplinkage void do_##name(struct pt_regs *regs, long error_code) \ +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; \ - conditional_sti(regs); \ - do_trap(trapnr, signr, str, regs, error_code, NULL); \ + do_trap(trapnr, signr, str, 0, regs, error_code, NULL); \ } -#define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \ -dotraplinkage void do_##name(struct pt_regs *regs, long error_code) \ +#define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr, irq) \ +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; \ @@ -253,68 +545,90 @@ dotraplinkage 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, &info); \ + do_trap(trapnr, signr, str, 0, 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) -#ifdef CONFIG_X86_32 -DO_ERROR(12, SIGBUS, "stack segment", stack_segment) -#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); +#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); \ } -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); - - 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); +#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(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(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) -dotraplinkage void __kprobes +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; - conditional_sti(regs); + cpu = get_cpu(); + tss = &per_cpu(init_tss, cpu); + thread = ¤t->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(); -#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)) @@ -336,12 +650,10 @@ 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)) @@ -378,8 +690,7 @@ 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. */ - reason = (reason & 0xf) | 4; - outb(reason, 0x61); + clear_mem_error(reason); } static notrace __kprobes void @@ -405,8 +716,7 @@ 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 /* @@ -429,6 +739,41 @@ 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; @@ -467,25 +812,22 @@ 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 } -dotraplinkage notrace __kprobes void -do_nmi(struct pt_regs *regs, long error_code) +notrace __kprobes void do_nmi(struct pt_regs *regs, long error_code) { + int cpu; + nmi_enter(); -#ifdef CONFIG_X86_32 - { int cpu; cpu = smp_processor_id(); ++nmi_count(cpu); } -#else - add_pda(__nmi_count, 1); -#endif + cpu = smp_processor_id(); + + ++nmi_count(cpu); if (!ignore_nmis) default_do_nmi(regs); @@ -505,44 +847,21 @@ void restart_nmi(void) acpi_nmi_enable(); } -/* May run on IST stack. */ -dotraplinkage void __kprobes do_int3(struct pt_regs *regs, long error_code) -{ #ifdef CONFIG_KPROBES +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; -#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); -} + /* + * This is an interrupt gate, because kprobes wants interrupts + * disabled. Normal trap handlers don't. + */ + restore_interrupts(regs); -#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; + do_trap(3, SIGTRAP, "int3", 1, regs, error_code, NULL); } #endif @@ -567,15 +886,15 @@ asmlinkage __kprobes struct pt_regs *sync_regs(struct pt_regs *eregs) * 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. */ -dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code) +void __kprobes do_debug(struct pt_regs *regs, long error_code) { struct task_struct *tsk = current; - unsigned long condition; + unsigned int condition; int si_code; + trace_hardirqs_fixup(); + get_debugreg(condition, 6); /* @@ -587,9 +906,9 @@ dotraplinkage 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 */ - preempt_conditional_sti(regs); + if (regs->flags & X86_EFLAGS_IF) + local_irq_enable(); /* Mask out spurious debug traps due to lazy DR7 setting */ if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) { @@ -597,10 +916,8 @@ dotraplinkage 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; @@ -610,11 +927,16 @@ dotraplinkage 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(condition); + si_code = get_si_code((unsigned long)condition); /* Ok, finally something we can handle */ send_sigtrap(tsk, regs, error_code, si_code); @@ -624,37 +946,18 @@ dotraplinkage 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 @@ -691,9 +994,7 @@ 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 */ @@ -721,18 +1022,9 @@ void math_error(void __user *ip) force_sig_info(SIGFPE, &info, task); } -dotraplinkage void do_coprocessor_error(struct pt_regs *regs, long error_code) +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); } @@ -784,12 +1076,8 @@ static void simd_math_error(void __user *ip) force_sig_info(SIGFPE, &info, task); } -dotraplinkage void -do_simd_coprocessor_error(struct pt_regs *regs, long error_code) +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; @@ -808,25 +1096,16 @@ 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 } -dotraplinkage void -do_spurious_interrupt_bug(struct pt_regs *regs, long error_code) +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()); @@ -845,15 +1124,6 @@ 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 @@ -886,24 +1156,14 @@ 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 @@ -912,54 +1172,12 @@ 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 +#endif /* CONFIG_MATH_EMULATION */ void __init trap_init(void) { -#ifdef CONFIG_X86_32 int i; -#endif #ifdef CONFIG_EISA void __iomem *p = early_ioremap(0x0FFFD9, 4); @@ -969,40 +1187,29 @@ void __init trap_init(void) early_iounmap(p, 4); #endif - set_intr_gate(0, ÷_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_trap_gate(0, ÷_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_task_gate(8, GDT_ENTRY_DOUBLEFAULT_TSS); -#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_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); 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); + set_trap_gate(15, &spurious_interrupt_bug); + set_trap_gate(16, &coprocessor_error); + set_trap_gate(17, &alignment_check); #ifdef CONFIG_X86_MCE - set_intr_gate_ist(18, &machine_check, MCE_STACK); + set_trap_gate(18, &machine_check); #endif - set_intr_gate(19, &simd_coprocessor_error); + set_trap_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); @@ -1015,20 +1222,36 @@ void __init trap_init(void) printk("done.\n"); } - set_system_trap_gate(SYSCALL_VECTOR, &system_call); + set_system_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/trunk/arch/x86/kernel/traps_64.c b/trunk/arch/x86/kernel/traps_64.c new file mode 100644 index 000000000000..9c0ac0cab013 --- /dev/null +++ b/trunk/arch/x86/kernel/traps_64.c @@ -0,0 +1,1214 @@ +/* + * Copyright (C) 1991, 1992 Linus Torvalds + * Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs + * + * Pentium III FXSR, SSE support + * Gareth Hughes , May 2000 + */ + +/* + * 'Traps.c' handles hardware traps and faults after we have saved some + * state in 'entry.S'. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(CONFIG_EDAC) +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +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, ""); + /* + * 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(" "); + } + } 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, ÷_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); diff --git a/trunk/arch/x86/mach-generic/es7000.c b/trunk/arch/x86/mach-generic/es7000.c index 6513d41ea21e..520cca0ee04e 100644 --- a/trunk/arch/x86/mach-generic/es7000.c +++ b/trunk/arch/x86/mach-generic/es7000.c @@ -47,26 +47,16 @@ 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 = 0; - int check_dsdt; - int ret = 0; - - /* check dsdt at first to avoid clear fix_map for oem_addr */ - check_dsdt = es7000_check_dsdt(); - + unsigned long oem_addr; if (!find_unisys_acpi_oem_table(&oem_addr)) { - if (check_dsdt) - ret = parse_unisys_oem((char *)oem_addr); + if (es7000_check_dsdt()) + return parse_unisys_oem((char *)oem_addr); else { setup_unisys(); - ret = 1; + return 1; } - /* - * we need to unmap it - */ - unmap_unisys_acpi_oem_table(oem_addr); } - return ret; + return 0; } #else static int __init acpi_madt_oem_check(char *oem_id, char *oem_table_id) diff --git a/trunk/arch/x86/mm/Makefile b/trunk/arch/x86/mm/Makefile index 59f89b434b45..dfb932dcf136 100644 --- a/trunk/arch/x86/mm/Makefile +++ b/trunk/arch/x86/mm/Makefile @@ -13,8 +13,12 @@ obj-$(CONFIG_MMIOTRACE) += mmiotrace.o mmiotrace-y := pf_in.o mmio-mod.o obj-$(CONFIG_MMIOTRACE_TEST) += testmmiotrace.o -obj-$(CONFIG_NUMA) += numa_$(BITS).o +ifeq ($(CONFIG_X86_32),y) +obj-$(CONFIG_NUMA) += discontig_32.o +else +obj-$(CONFIG_NUMA) += numa_64.o obj-$(CONFIG_K8_NUMA) += k8topology_64.o +endif obj-$(CONFIG_ACPI_NUMA) += srat_$(BITS).o obj-$(CONFIG_MEMTEST) += memtest.o diff --git a/trunk/arch/x86/mm/numa_32.c b/trunk/arch/x86/mm/discontig_32.c similarity index 100% rename from trunk/arch/x86/mm/numa_32.c rename to trunk/arch/x86/mm/discontig_32.c diff --git a/trunk/arch/x86/mm/fault.c b/trunk/arch/x86/mm/fault.c index 3f2b8962cbd0..a742d753d5b0 100644 --- a/trunk/arch/x86/mm/fault.c +++ b/trunk/arch/x86/mm/fault.c @@ -592,6 +592,11 @@ 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); diff --git a/trunk/arch/x86/mm/gup.c b/trunk/arch/x86/mm/gup.c index 4ba373c5b8c8..007bb06c7504 100644 --- a/trunk/arch/x86/mm/gup.c +++ b/trunk/arch/x86/mm/gup.c @@ -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_flags(pte) & (mask | _PAGE_SPECIAL)) != mask) { + if ((pte_val(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_flags(pte) & mask) != mask) + if ((pte_val(pte) & mask) != mask) return 0; /* hugepages are never "special" */ - VM_BUG_ON(pte_flags(pte) & _PAGE_SPECIAL); + VM_BUG_ON(pte_val(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_flags(pte) & mask) != mask) + if ((pte_val(pte) & mask) != mask) return 0; /* hugepages are never "special" */ - VM_BUG_ON(pte_flags(pte) & _PAGE_SPECIAL); + VM_BUG_ON(pte_val(pte) & _PAGE_SPECIAL); VM_BUG_ON(!pfn_valid(pte_pfn(pte))); refs = 0; diff --git a/trunk/arch/x86/mm/init_32.c b/trunk/arch/x86/mm/init_32.c index 8396868e82c5..bbe044dbe014 100644 --- a/trunk/arch/x86/mm/init_32.c +++ b/trunk/arch/x86/mm/init_32.c @@ -558,7 +558,7 @@ void zap_low_mappings(void) int nx_enabled; -pteval_t __supported_pte_mask __read_mostly = ~(_PAGE_NX | _PAGE_GLOBAL | _PAGE_IOMAP); +pteval_t __supported_pte_mask __read_mostly = ~(_PAGE_NX | _PAGE_GLOBAL); EXPORT_SYMBOL_GPL(__supported_pte_mask); #ifdef CONFIG_X86_PAE diff --git a/trunk/arch/x86/mm/init_64.c b/trunk/arch/x86/mm/init_64.c index b8e461d49412..3e10054c5731 100644 --- a/trunk/arch/x86/mm/init_64.c +++ b/trunk/arch/x86/mm/init_64.c @@ -89,7 +89,7 @@ early_param("gbpages", parse_direct_gbpages_on); int after_bootmem; -pteval_t __supported_pte_mask __read_mostly = ~_PAGE_IOMAP; +unsigned long __supported_pte_mask __read_mostly = ~0UL; EXPORT_SYMBOL_GPL(__supported_pte_mask); static int do_not_nx __cpuinitdata; @@ -196,6 +196,9 @@ 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); /* @@ -310,7 +313,7 @@ static __ref void *alloc_low_page(unsigned long *phys) if (pfn >= table_top) panic("alloc_low_page: ran out of memory"); - adr = early_memremap(pfn * PAGE_SIZE, PAGE_SIZE); + adr = early_ioremap(pfn * PAGE_SIZE, PAGE_SIZE); memset(adr, 0, PAGE_SIZE); *phys = pfn * PAGE_SIZE; return adr; @@ -746,7 +749,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--; } diff --git a/trunk/arch/x86/mm/ioremap.c b/trunk/arch/x86/mm/ioremap.c index e4c43ec71b29..8cbeda15cd29 100644 --- a/trunk/arch/x86/mm/ioremap.c +++ b/trunk/arch/x86/mm/ioremap.c @@ -45,27 +45,6 @@ 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) @@ -77,24 +56,13 @@ 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); - VIRTUAL_BUG_ON(system_state != SYSTEM_BOOTING && - is_vmalloc_addr((void *) x)); + VIRTUAL_BUG_ON(x < PAGE_OFFSET || (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) @@ -274,16 +242,16 @@ static void __iomem *__ioremap_caller(resource_size_t phys_addr, switch (prot_val) { case _PAGE_CACHE_UC: default: - prot = PAGE_KERNEL_IO_NOCACHE; + prot = PAGE_KERNEL_NOCACHE; break; case _PAGE_CACHE_UC_MINUS: - prot = PAGE_KERNEL_IO_UC_MINUS; + prot = PAGE_KERNEL_UC_MINUS; break; case _PAGE_CACHE_WC: - prot = PAGE_KERNEL_IO_WC; + prot = PAGE_KERNEL_WC; break; case _PAGE_CACHE_WB: - prot = PAGE_KERNEL_IO; + prot = PAGE_KERNEL; break; } @@ -600,12 +568,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, pgprot_t prot) + unsigned long phys) { if (after_paging_init) - __set_fixmap(idx, phys, prot); + set_fixmap(idx, phys); else - __early_set_fixmap(idx, phys, prot); + __early_set_fixmap(idx, phys, PAGE_KERNEL); } static inline void __init early_clear_fixmap(enum fixed_addresses idx) @@ -616,22 +584,16 @@ static inline void __init early_clear_fixmap(enum fixed_addresses idx) __early_set_fixmap(idx, 0, __pgprot(0)); } -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) -{ - int count = 0; - int i; - for (i = 0; i < FIX_BTMAPS_SLOTS; i++) - if (prev_map[i]) - count++; +static int __initdata early_ioremap_nested; - if (!count) +static int __init check_early_ioremap_leak(void) +{ + if (!early_ioremap_nested) return 0; WARN(1, KERN_WARNING "Debug warning: early ioremap leak of %d areas detected.\n", - count); + early_ioremap_nested); printk(KERN_WARNING "please boot with early_ioremap_debug and report the dmesg.\n"); @@ -639,33 +601,18 @@ static int __init check_early_ioremap_leak(void) } late_initcall(check_early_ioremap_leak); -static void __init *__early_ioremap(unsigned long phys_addr, unsigned long size, pgprot_t prot) +void __init *early_ioremap(unsigned long phys_addr, unsigned long size) { unsigned long offset, last_addr; - unsigned int nrpages; + unsigned int nrpages, nesting; enum fixed_addresses idx0, idx; - int i, slot; WARN_ON(system_state != SYSTEM_BOOTING); - 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; - } - + nesting = early_ioremap_nested; if (early_ioremap_debug) { printk(KERN_INFO "early_ioremap(%08lx, %08lx) [%d] => ", - phys_addr, size, slot); + phys_addr, size, nesting); dump_stack(); } @@ -676,7 +623,11 @@ static void __init *__early_ioremap(unsigned long phys_addr, unsigned long size, return NULL; } - prev_size[slot] = size; + if (nesting >= FIX_BTMAPS_NESTING) { + WARN_ON(1); + return NULL; + } + early_ioremap_nested++; /* * Mappings have to be page-aligned */ @@ -696,10 +647,10 @@ static void __init *__early_ioremap(unsigned long phys_addr, unsigned long size, /* * Ok, go for it.. */ - idx0 = FIX_BTMAP_BEGIN - NR_FIX_BTMAPS*slot; + idx0 = FIX_BTMAP_BEGIN - NR_FIX_BTMAPS*nesting; idx = idx0; while (nrpages > 0) { - early_set_fixmap(idx, phys_addr, prot); + early_set_fixmap(idx, phys_addr); phys_addr += PAGE_SIZE; --idx; --nrpages; @@ -707,20 +658,7 @@ static 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)); - 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); + return (void *) (offset + fix_to_virt(idx0)); } void __init early_iounmap(void *addr, unsigned long size) @@ -729,33 +667,15 @@ void __init early_iounmap(void *addr, unsigned long size) unsigned long offset; unsigned int nrpages; enum fixed_addresses idx; - int i, slot; - - slot = -1; - for (i = 0; i < FIX_BTMAPS_SLOTS; i++) { - if (prev_map[i] == addr) { - slot = i; - break; - } - } + int nesting; - 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); + nesting = --early_ioremap_nested; + if (WARN_ON(nesting < 0)) return; - } if (early_ioremap_debug) { printk(KERN_INFO "early_iounmap(%p, %08lx) [%d]\n", addr, - size, slot); + size, nesting); dump_stack(); } @@ -767,13 +687,12 @@ 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*slot; + idx = FIX_BTMAP_BEGIN - NR_FIX_BTMAPS*nesting; while (nrpages > 0) { early_clear_fixmap(idx); --idx; --nrpages; } - prev_map[slot] = 0; } void __this_fixmap_does_not_exist(void) diff --git a/trunk/arch/x86/mm/srat_64.c b/trunk/arch/x86/mm/srat_64.c index 51c0a2fc14fe..1b4763e26ea9 100644 --- a/trunk/arch/x86/mm/srat_64.c +++ b/trunk/arch/x86/mm/srat_64.c @@ -138,7 +138,7 @@ acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *pa) return; } - if (get_uv_system_type() >= UV_X2APIC) + if (is_uv_system()) apic_id = (pa->apic_id << 8) | pa->local_sapic_eid; else apic_id = pa->apic_id; diff --git a/trunk/arch/x86/oprofile/Makefile b/trunk/arch/x86/oprofile/Makefile index 446902b2a6b6..30f3eb366667 100644 --- a/trunk/arch/x86/oprofile/Makefile +++ b/trunk/arch/x86/oprofile/Makefile @@ -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_amd.o \ +oprofile-$(CONFIG_X86_LOCAL_APIC) += nmi_int.o op_model_athlon.o \ op_model_ppro.o op_model_p4.o oprofile-$(CONFIG_X86_IO_APIC) += nmi_timer_int.o diff --git a/trunk/arch/x86/oprofile/nmi_int.c b/trunk/arch/x86/oprofile/nmi_int.c index 57f6c9088081..8a5f1614a3d5 100644 --- a/trunk/arch/x86/oprofile/nmi_int.c +++ b/trunk/arch/x86/oprofile/nmi_int.c @@ -1,11 +1,10 @@ /** * @file nmi_int.c * - * @remark Copyright 2002-2008 OProfile authors + * @remark Copyright 2002 OProfile authors * @remark Read the file COPYING * * @author John Levon - * @author Robert Richter */ #include @@ -440,7 +439,6 @@ 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; @@ -453,23 +451,19 @@ int __init op_nmi_init(struct oprofile_operations *ops) default: return -ENODEV; case 6: - model = &op_amd_spec; + model = &op_athlon_spec; cpu_type = "i386/athlon"; break; case 0xf: - model = &op_amd_spec; + model = &op_athlon_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_amd_spec; + model = &op_athlon_spec; cpu_type = "x86-64/family10"; break; - case 0x11: - model = &op_amd_spec; - cpu_type = "x86-64/family11h"; - break; } break; @@ -496,24 +490,17 @@ int __init op_nmi_init(struct oprofile_operations *ops) return -ENODEV; } + init_sysfs(); #ifdef CONFIG_SMP register_cpu_notifier(&oprofile_cpu_nb); #endif - /* default values, can be overwritten by model */ + using_nmi = 1; 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; } @@ -526,6 +513,4 @@ void op_nmi_exit(void) unregister_cpu_notifier(&oprofile_cpu_nb); #endif } - if (model->exit) - model->exit(); } diff --git a/trunk/arch/x86/oprofile/op_model_amd.c b/trunk/arch/x86/oprofile/op_model_amd.c deleted file mode 100644 index d9faf607b3a6..000000000000 --- a/trunk/arch/x86/oprofile/op_model_amd.c +++ /dev/null @@ -1,543 +0,0 @@ -/* - * @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 - * @author Barry Kasindorf -*/ - -#include -#include -#include - -#include -#include -#include - -#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/trunk/arch/x86/oprofile/op_model_athlon.c b/trunk/arch/x86/oprofile/op_model_athlon.c new file mode 100644 index 000000000000..3d534879a9dc --- /dev/null +++ b/trunk/arch/x86/oprofile/op_model_athlon.c @@ -0,0 +1,190 @@ +/* + * @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 +#include +#include +#include + +#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 +}; diff --git a/trunk/arch/x86/oprofile/op_x86_model.h b/trunk/arch/x86/oprofile/op_x86_model.h index 05a0261ba0c3..45b605fa71d0 100644 --- a/trunk/arch/x86/oprofile/op_x86_model.h +++ b/trunk/arch/x86/oprofile/op_x86_model.h @@ -32,8 +32,6 @@ 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); @@ -48,6 +46,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_amd_spec; +extern struct op_x86_model_spec const op_athlon_spec; #endif /* OP_X86_MODEL_H */ diff --git a/trunk/arch/x86/pci/fixup.c b/trunk/arch/x86/pci/fixup.c index 3c27a809393b..4bdaa590375d 100644 --- a/trunk/arch/x86/pci/fixup.c +++ b/trunk/arch/x86/pci/fixup.c @@ -511,31 +511,3 @@ 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); diff --git a/trunk/drivers/bluetooth/hci_ldisc.c b/trunk/drivers/bluetooth/hci_ldisc.c index 4426bb552bd9..8dfcf77cb717 100644 --- a/trunk/drivers/bluetooth/hci_ldisc.c +++ b/trunk/drivers/bluetooth/hci_ldisc.c @@ -484,7 +484,7 @@ static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file * file, return -EUNATCH; default: - err = n_tty_ioctl_helper(tty, file, cmd, arg); + err = n_tty_ioctl(tty, file, cmd, arg); break; }; diff --git a/trunk/drivers/char/Kconfig b/trunk/drivers/char/Kconfig index 700ff9679457..caff85149b9d 100644 --- a/trunk/drivers/char/Kconfig +++ b/trunk/drivers/char/Kconfig @@ -350,7 +350,7 @@ config STALDRV config STALLION tristate "Stallion EasyIO or EC8/32 support" - depends on STALDRV && (ISA || EISA || PCI) + depends on STALDRV && BROKEN_ON_SMP && (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 && (ISA || EISA || PCI) + depends on STALDRV && BROKEN_ON_SMP && (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 diff --git a/trunk/drivers/char/Makefile b/trunk/drivers/char/Makefile index 1a4247dccac4..6850f6da7576 100644 --- a/trunk/drivers/char/Makefile +++ b/trunk/drivers/char/Makefile @@ -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 tty_buffer.o tty_port.o +obj-y += mem.o random.o tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o obj-$(CONFIG_LEGACY_PTYS) += pty.o obj-$(CONFIG_UNIX98_PTYS) += pty.o diff --git a/trunk/drivers/char/amiserial.c b/trunk/drivers/char/amiserial.c index 98821f97583c..6e763e3f5a81 100644 --- a/trunk/drivers/char/amiserial.c +++ b/trunk/drivers/char/amiserial.c @@ -837,6 +837,9 @@ 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")) @@ -889,6 +892,9 @@ 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")) diff --git a/trunk/drivers/char/applicom.c b/trunk/drivers/char/applicom.c index b899d9182c7d..31d08b641f5b 100644 --- a/trunk/drivers/char/applicom.c +++ b/trunk/drivers/char/applicom.c @@ -712,7 +712,8 @@ static int ac_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un IndexCard = adgl->num_card-1; - if(cmd != 6 && ((IndexCard >= MAX_BOARD) || !apbs[IndexCard].RamIO)) { + if(cmd != 0 && 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); @@ -831,7 +832,8 @@ static int ac_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un } break; default: - ret = -ENOTTY; + printk(KERN_INFO "APPLICOM driver ioctl, unknown function code %d\n",cmd) ; + ret = -EINVAL; break; } Dummy = readb(apbs[IndexCard].RamIO + VERS); diff --git a/trunk/drivers/char/cyclades.c b/trunk/drivers/char/cyclades.c index 5e5b1dc1a0a7..fe6d774fe2e4 100644 --- a/trunk/drivers/char/cyclades.c +++ b/trunk/drivers/char/cyclades.c @@ -4993,14 +4993,12 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev, device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) { card_name = "Cyclom-Y"; - addr0 = ioremap_nocache(pci_resource_start(pdev, 0), - CyPCI_Yctl); + addr0 = pci_iomap(pdev, 0, CyPCI_Yctl); if (addr0 == NULL) { dev_err(&pdev->dev, "can't remap ctl region\n"); goto err_reg; } - addr2 = ioremap_nocache(pci_resource_start(pdev, 2), - CyPCI_Ywin); + addr2 = pci_iomap(pdev, 2, CyPCI_Ywin); if (addr2 == NULL) { dev_err(&pdev->dev, "can't remap base region\n"); goto err_unmap; @@ -5015,8 +5013,7 @@ 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 = ioremap_nocache(pci_resource_start(pdev, 0), - CyPCI_Zctl); + ctl_addr = addr0 = pci_iomap(pdev, 0, CyPCI_Zctl); if (addr0 == NULL) { dev_err(&pdev->dev, "can't remap ctl region\n"); goto err_reg; @@ -5029,8 +5026,8 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev, mailbox = (u32)readl(&ctl_addr->mail_box_0); - addr2 = ioremap_nocache(pci_resource_start(pdev, 2), - mailbox == ZE_V1 ? CyPCI_Ze_win : CyPCI_Zwin); + addr2 = pci_iomap(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; @@ -5162,9 +5159,9 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev, cy_card[card_no].base_addr = NULL; free_irq(irq, &cy_card[card_no]); err_unmap: - iounmap(addr0); + pci_iounmap(pdev, addr0); if (addr2) - iounmap(addr2); + pci_iounmap(pdev, addr2); err_reg: pci_release_regions(pdev); err_dis: @@ -5189,9 +5186,9 @@ static void __devexit cy_pci_remove(struct pci_dev *pdev) cy_writew(cinfo->ctl_addr + 0x68, readw(cinfo->ctl_addr + 0x68) & ~0x0900); - iounmap(cinfo->base_addr); + pci_iounmap(pdev, cinfo->base_addr); if (cinfo->ctl_addr) - iounmap(cinfo->ctl_addr); + pci_iounmap(pdev, cinfo->ctl_addr); if (cinfo->irq #ifndef CONFIG_CYZ_INTR && !IS_CYC_Z(*cinfo) diff --git a/trunk/drivers/char/epca.c b/trunk/drivers/char/epca.c index 4998b2761e8f..456e4ede049f 100644 --- a/trunk/drivers/char/epca.c +++ b/trunk/drivers/char/epca.c @@ -1376,7 +1376,6 @@ 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); @@ -1511,6 +1510,10 @@ 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); } diff --git a/trunk/drivers/char/generic_serial.c b/trunk/drivers/char/generic_serial.c index c6090f84a2e4..19d3afb0e50c 100644 --- a/trunk/drivers/char/generic_serial.c +++ b/trunk/drivers/char/generic_serial.c @@ -54,6 +54,8 @@ 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; @@ -95,6 +97,8 @@ int gs_write(struct tty_struct * tty, func_enter (); + if (!tty) return 0; + port = tty->driver_data; if (!port) return 0; @@ -181,6 +185,7 @@ 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; @@ -269,6 +274,8 @@ void gs_flush_buffer(struct tty_struct *tty) func_enter (); + if (!tty) return; + port = tty->driver_data; if (!port) return; @@ -289,6 +296,8 @@ void gs_flush_chars(struct tty_struct * tty) func_enter (); + if (!tty) return; + port = tty->driver_data; if (!port) return; @@ -312,6 +321,8 @@ void gs_stop(struct tty_struct * tty) func_enter (); + if (!tty) return; + port = tty->driver_data; if (!port) return; @@ -330,6 +341,8 @@ void gs_start(struct tty_struct * tty) { struct gs_port *port; + if (!tty) return; + port = tty->driver_data; if (!port) return; @@ -380,6 +393,8 @@ void gs_hangup(struct tty_struct *tty) func_enter (); + if (!tty) return; + port = tty->driver_data; tty = port->port.tty; if (!tty) @@ -411,6 +426,8 @@ 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 @@ -506,6 +523,8 @@ 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; @@ -602,6 +621,8 @@ void gs_set_termios (struct tty_struct * tty, func_enter(); + if (!tty) return; + port = tty->driver_data; if (!port) return; diff --git a/trunk/drivers/char/hpet.c b/trunk/drivers/char/hpet.c index f3cfb4c76125..b3f5dbc6d880 100644 --- a/trunk/drivers/char/hpet.c +++ b/trunk/drivers/char/hpet.c @@ -53,11 +53,6 @@ #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) @@ -82,7 +77,7 @@ static struct clocksource clocksource_hpet = { .rating = 250, .read = read_hpet, .mask = CLOCKSOURCE_MASK(64), - .mult = 0, /* to be calculated */ + .mult = 0, /*to be caluclated*/ .shift = 10, .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; @@ -91,6 +86,8 @@ 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) @@ -102,6 +99,7 @@ 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; @@ -175,6 +173,11 @@ 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); @@ -182,67 +185,6 @@ 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; @@ -257,7 +199,8 @@ 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) + if (hpetp->hp_dev[i].hd_flags & HPET_OPEN + || hpetp->hp_dev[i].hd_task) continue; else { devp = &hpetp->hp_dev[i]; @@ -276,8 +219,6 @@ static int hpet_open(struct inode *inode, struct file *file) spin_unlock_irq(&hpet_lock); unlock_kernel(); - hpet_timer_set_irq(devp); - return 0; } @@ -500,11 +441,7 @@ static int hpet_ioctl_ieon(struct hpet_dev *devp) devp->hd_irq = irq; t = devp->hd_ireqfreq; v = readq(&timer->hpet_config); - - /* 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; + g = v | Tn_INT_ENB_CNF_MASK; if (devp->hd_flags & HPET_PERIODIC) { write_counter(t, &timer->hpet_compare); @@ -514,12 +451,6 @@ 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 { @@ -673,6 +604,57 @@ 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, @@ -764,7 +746,6 @@ 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. @@ -828,13 +809,9 @@ int hpet_alloc(struct hpet_data *hdp) printk("%s %d", i > 0 ? "," : "", hdp->hd_irq[i]); printk("\n"); - 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); + 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); mcfg = readq(&hpet->hpet_config); if ((mcfg & HPET_ENABLE_CNF_MASK) == 0) { @@ -897,6 +874,8 @@ 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; } @@ -912,6 +891,8 @@ 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; } diff --git a/trunk/drivers/char/hvc_console.c b/trunk/drivers/char/hvc_console.c index ec7aded0a2df..fd64137b1ab9 100644 --- a/trunk/drivers/char/hvc_console.c +++ b/trunk/drivers/char/hvc_console.c @@ -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; } diff --git a/trunk/drivers/char/ip2/Makefile b/trunk/drivers/char/ip2/Makefile index bc397d92b499..939618f62fe1 100644 --- a/trunk/drivers/char/ip2/Makefile +++ b/trunk/drivers/char/ip2/Makefile @@ -4,5 +4,5 @@ obj-$(CONFIG_COMPUTONE) += ip2.o -ip2-objs := ip2main.o +ip2-objs := ip2base.o ip2main.o diff --git a/trunk/drivers/char/ip2/i2ellis.c b/trunk/drivers/char/ip2/i2ellis.c index 29db44de399f..3601017f58cf 100644 --- a/trunk/drivers/char/ip2/i2ellis.c +++ b/trunk/drivers/char/ip2/i2ellis.c @@ -68,6 +68,38 @@ 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 diff --git a/trunk/drivers/char/ip2/i2ellis.h b/trunk/drivers/char/ip2/i2ellis.h index fb6df2456018..c88a64e527aa 100644 --- a/trunk/drivers/char/ip2/i2ellis.h +++ b/trunk/drivers/char/ip2/i2ellis.h @@ -511,6 +511,7 @@ 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 -- @@ -522,6 +523,7 @@ 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/trunk/drivers/char/ip2/ip2base.c b/trunk/drivers/char/ip2/ip2base.c new file mode 100644 index 000000000000..8155e247c04b --- /dev/null +++ b/trunk/drivers/char/ip2/ip2base.c @@ -0,0 +1,108 @@ +// 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 +#include +#include + +#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 */ diff --git a/trunk/drivers/char/ip2/ip2main.c b/trunk/drivers/char/ip2/ip2main.c index 6774572d3759..689f9dcd3b86 100644 --- a/trunk/drivers/char/ip2/ip2main.c +++ b/trunk/drivers/char/ip2/ip2main.c @@ -150,12 +150,15 @@ static int ip2_read_proc(char *, char **, off_t, int, int *, void * ); /*************/ /* String constants to identify ourselves */ -static const char pcName[] = "Computone IntelliPort Plus multiport driver"; -static const char pcVersion[] = "1.2.14"; +static char *pcName = "Computone IntelliPort Plus multiport driver"; +static char *pcVersion = "1.2.14"; /* String constants for port names */ -static const char pcDriver_name[] = "ip2"; -static const char pcIpl[] = "ip2ipl"; +static char *pcDriver_name = "ip2"; +static char *pcIpl = "ip2ipl"; + +// cheezy kludge or genius - you decide? +int ip2_loadmain(int *, int *); /***********************/ /* Function Prototypes */ @@ -237,8 +240,8 @@ static const struct file_operations ip2_ipl = { .open = ip2_ipl_open, }; -static unsigned long irq_counter; -static unsigned long bh_counter; +static unsigned long irq_counter = 0; +static unsigned long bh_counter = 0; // Use immediate queue to service interrupts #define USE_IQI @@ -249,6 +252,7 @@ static unsigned long bh_counter; */ #define POLL_TIMEOUT (jiffies + 1) static DEFINE_TIMER(PollTimer, ip2_poll, 0, 0); +static char TimerOn; #ifdef IP2DEBUG_TRACE /* Trace (debug) buffer data */ @@ -264,8 +268,8 @@ static int tracewrap; /**********/ #if defined(MODULE) && defined(IP2DEBUG_OPEN) -#define DBG_CNT(s) printk(KERN_DEBUG "(%s): [%x] ttyc=%d, modc=%x -> %s\n", \ - tty->name,(pCh->flags), \ +#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, \ tty->count,/*GET_USE_COUNT(module)*/0,s) #else #define DBG_CNT(s) @@ -283,9 +287,8 @@ static int tracewrap; MODULE_AUTHOR("Doug McNash"); MODULE_DESCRIPTION("Computone IntelliPort Plus Driver"); -MODULE_LICENSE("GPL"); -static int poll_only; +static int poll_only = 0; static int Eisa_irq; static int Eisa_slot; @@ -294,46 +297,34 @@ 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 irqs we have */ +// Some functions to keep track of what irq's we have -static int __init is_valid_irq(int irq) +static int +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 __init mark_requested_irq(char irq) +static void +mark_requested_irq( char irq ) { rirqs[iindx++] = irq; } -static int __exit clear_requested_irq(char irq) +#ifdef MODULE +static int +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; @@ -341,15 +332,17 @@ static int __exit 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; } @@ -368,45 +361,53 @@ static int 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. */ /******************************************************************************/ -static void __exit ip2_cleanup_module(void) +#ifdef MODULE +void __exit +ip2_cleanup_module(void) { int err; int i; - del_timer_sync(&PollTimer); +#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; + } /* 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); - err = tty_unregister_driver(ip2_tty_driver); - if (err) - printk(KERN_ERR "IP2: failed to unregister tty driver (%d)\n", - err); + if ( ( err = tty_unregister_driver ( ip2_tty_driver ) ) ) { + 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 @@ -416,18 +417,24 @@ static void __exit ip2_cleanup_module(void) ip2config.pci_dev[i] = NULL; } #endif - pB = i2BoardPtrTable[i]; - if (pB != NULL) { - kfree(pB); + if ((pB = i2BoardPtrTable[i]) != 0 ) { + 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, @@ -487,168 +494,139 @@ static const struct firmware *ip2_request_firmware(void) return fw; } -#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 +ip2_loadmain(int *iop, int *irqp) { int i, j, box; int err = 0; + static int loaded; i2eBordStrPtr pB = NULL; int rc = -1; - struct pci_dev *pdev = NULL; + static struct pci_dev *pci_dev_i = NULL; const struct firmware *fw = NULL; - 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); + 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) { - 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]; + 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]; + } + } } poll_only = !poll_only; /* Announce our presence */ - printk(KERN_INFO "%s version %s\n", pcName, pcVersion); + 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++; 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; - 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; + } 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; case PCI: #ifdef CONFIG_PCI - { - u32 addr; - int status; + { + int status; - 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; - } + 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(pdev)) { - dev_err(&pdev->dev, "can't enable device\n"); - break; + 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"); + } + +// 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); + } } - 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 enabled.\n"); - printk(KERN_ERR "IP2: Recompile kernel with CONFIG_PCI " - "defined!\n"); + 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"); #endif /* CONFIG_PCI */ break; case EISA: - ip2config.addr[i] = find_eisa_board(Eisa_slot + 1); - if (ip2config.addr[i] != 0) { + if ( (ip2config.addr[i] = find_eisa_board( Eisa_slot + 1 )) != 0) { /* Eisa_irq set as side effect, boo */ ip2config.type[i] = EISA; } @@ -656,32 +634,31 @@ static int __init ip2_loadmain(void) break; } /* switch */ } /* for */ - pci_dev_put(pdev); + if (pci_dev_i) + pci_dev_put(pci_dev_i); - 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) { - pB = i2BoardPtrTable[i]; - if (pB != NULL) { - iiResetDelay(pB); + for ( i = 0; i < IP2_MAX_BOARDS; ++i ) { + if ( ( pB = i2BoardPtrTable[i] ) != 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) @@ -692,7 +669,7 @@ static int __init ip2_loadmain(void) 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"; @@ -703,23 +680,20 @@ static int __init ip2_loadmain(void) 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 ); - err = tty_register_driver(ip2_tty_driver); - if (err) { - printk(KERN_ERR "IP2: failed to register tty driver\n"); + /* Register the tty devices. */ + if ( ( err = tty_register_driver ( ip2_tty_driver ) ) ) { + printk(KERN_ERR "IP2: failed to register tty driver (%d)\n", err); put_tty_driver(ip2_tty_driver); - 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); + 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 ); } else { /* create the sysfs class */ ip2_class = class_create(THIS_MODULE, "ip2"); @@ -731,86 +705,84 @@ static int __init ip2_loadmain(void) /* Register the read_procmem thing */ if (!proc_create("ip2mem",0,NULL,&ip2mem_proc_fops)) { printk(KERN_ERR "IP2: failed to register read_procmem\n"); - return -EIO; /* leaking resources */ - } - - ip2trace(ITRC_NO_PORT, ITRC_INIT, 4, 0); - /* Register the interrupt handler or poll handler, depending upon the - * specified interrupt. - */ + } else { - for (i = 0; i < IP2_MAX_BOARDS; ++i) { - if (ip2config.addr[i] == 0) - continue; + ip2trace (ITRC_NO_PORT, ITRC_INIT, 4, 0 ); + /* Register the interrupt handler or poll handler, depending upon the + * specified interrupt. + */ - 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); - } + for( i = 0; i < IP2_MAX_BOARDS; ++i ) { + if ( 0 == ip2config.addr[i] ) { + continue; + } - 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 (!timer_pending(&PollTimer)) { - mod_timer(&PollTimer, POLL_TIMEOUT); - printk(KERN_INFO "IP2: polling\n"); + 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); + } + } + } } - } 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); + + 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; - 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 ( 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). */ + } } - } - - for (i = 0; i < IP2_MAX_BOARDS; ++i) { - if (i2BoardPtrTable[i]) { - /* set and enable board interrupt */ - set_irq(i, ip2config.irq[i]); + for( i = 0; i < IP2_MAX_BOARDS; ++i ) { + if ( i2BoardPtrTable[i] ) { + set_irq( i, ip2config.irq[i] ); /* set and enable board interrupt */ + } } } - - ip2trace(ITRC_NO_PORT, ITRC_INIT, ITRC_RETURN, 0); - - return 0; + ip2trace (ITRC_NO_PORT, ITRC_INIT, ITRC_RETURN, 0 ); + goto out; out_chrdev: unregister_chrdev(IP2_IPL_MAJOR, "ip2"); - /* unregister and put tty here */ +out: return err; } -module_init(ip2_loadmain); /******************************************************************************/ /* Function: ip2_init_board() */ @@ -1227,8 +1199,9 @@ ip2_polled_interrupt(void) { int i; i2eBordStrPtr pB; + const int irq = 0; - ip2trace(ITRC_NO_PORT, ITRC_INTR, 99, 1, 0); + ip2trace (ITRC_NO_PORT, ITRC_INTR, 99, 1, irq ); /* Service just the boards on the list using this irq */ for( i = 0; i < i2nBoards; ++i ) { @@ -1237,8 +1210,9 @@ 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 == 0) + if ( pB && (pB->i2eUsingIrq == irq) ) { ip2_irq_work(pB); + } } ++irq_counter; @@ -1276,12 +1250,16 @@ 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(); - mod_timer(&PollTimer, POLL_TIMEOUT); + PollTimer.expires = POLL_TIMEOUT; + add_timer( &PollTimer ); + TimerOn = 1; ip2trace (ITRC_NO_PORT, ITRC_INTR, ITRC_RETURN, 0 ); } @@ -2893,7 +2871,7 @@ ip2_ipl_ioctl (struct file *pFile, UINT cmd, ULONG arg ) case 13: switch ( cmd ) { case 64: /* Driver - ip2stat */ - rc = put_user(-1, pIndex++ ); + rc = put_user(ip2_tty_driver->refcount, pIndex++ ); rc = put_user(irq_counter, pIndex++ ); rc = put_user(bh_counter, pIndex++ ); break; diff --git a/trunk/drivers/char/isicom.c b/trunk/drivers/char/isicom.c index 7d30ee1d3fca..8f7cc190b62d 100644 --- a/trunk/drivers/char/isicom.c +++ b/trunk/drivers/char/isicom.c @@ -421,16 +421,17 @@ 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; @@ -488,8 +489,6 @@ 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 */ @@ -548,7 +547,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } - tty = tty_port_tty_get(&port->port); + tty = port->port.tty; if (tty == NULL) { word_count = byte_count >> 1; while (byte_count > 1) { @@ -589,7 +588,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id) } if (port->port.flags & ASYNC_CTS_FLOW) { - if (tty->hw_stopped) { + if (port->port.tty->hw_stopped) { if (header & ISI_CTS) { port->port.tty->hw_stopped = 0; /* start tx ing */ @@ -598,7 +597,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id) tty_wakeup(tty); } } else if (!(header & ISI_CTS)) { - tty->hw_stopped = 1; + port->port.tty->hw_stopped = 1; /* stop tx ing */ port->status &= ~(ISI_TXOK | ISI_CTS); } @@ -661,21 +660,24 @@ 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 tty_struct *tty) +static void isicom_config_port(struct isi_port *port) { - 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) { @@ -688,7 +690,7 @@ static void isicom_config_port(struct tty_struct *tty) /* 1,2,3,4 => 57.6, 115.2, 230, 460 kbps resp. */ if (baud < 1 || baud > 4) - tty->termios->c_cflag &= ~CBAUDEX; + port->port.tty->termios->c_cflag &= ~CBAUDEX; else baud += 15; } @@ -795,9 +797,8 @@ static inline void isicom_setup_board(struct isi_board *bp) spin_unlock_irqrestore(&bp->card_lock, flags); } -static int isicom_setup_port(struct tty_struct *tty) +static int isicom_setup_port(struct isi_port *port) { - struct isi_port *port = tty->driver_data; struct isi_board *card = port->card; unsigned long flags; @@ -807,7 +808,8 @@ static int isicom_setup_port(struct tty_struct *tty) return -ENOMEM; spin_lock_irqsave(&card->card_lock, flags); - clear_bit(TTY_IO_ERROR, &tty->flags); + if (port->port.tty) + clear_bit(TTY_IO_ERROR, &port->port.tty->flags); if (port->port.count == 1) card->count++; @@ -821,7 +823,7 @@ static int isicom_setup_port(struct tty_struct *tty) InterruptTheCard(card->base); } - isicom_config_port(tty); + isicom_config_port(port); port->port.flags |= ASYNC_INITIALIZED; spin_unlock_irqrestore(&card->card_lock, flags); @@ -932,8 +934,8 @@ static int isicom_open(struct tty_struct *tty, struct file *filp) port->port.count++; tty->driver_data = port; - tty_port_tty_set(&port->port, tty); - error = isicom_setup_port(tty); + port->port.tty = tty; + error = isicom_setup_port(port); if (error == 0) error = block_til_ready(tty, filp, port); return error; @@ -953,17 +955,15 @@ static void isicom_shutdown_port(struct isi_port *port) struct isi_board *card = port->card; struct tty_struct *tty; - tty = tty_port_tty_get(&port->port); + tty = port->port.tty; - if (!(port->port.flags & ASYNC_INITIALIZED)) { - tty_kref_put(tty); + if (!(port->port.flags & ASYNC_INITIALIZED)) return; - } tty_port_free_xmit_buf(&port->port); port->port.flags &= ~ASYNC_INITIALIZED; /* 3rd October 2000 : Vinayak P Risbud */ - tty_port_tty_set(&port->port, NULL); + port->port.tty = NULL; /*Fix done by Anil .S on 30-04-2001 remote login through isi port has dtr toggle problem @@ -1243,10 +1243,9 @@ static int isicom_tiocmset(struct tty_struct *tty, struct file *file, return 0; } -static int isicom_set_serial_info(struct tty_struct *tty, - struct serial_struct __user *info) +static int isicom_set_serial_info(struct isi_port *port, + struct serial_struct __user *info) { - struct isi_port *port = tty->driver_data; struct serial_struct newinfo; int reconfig_port; @@ -1277,7 +1276,7 @@ static int isicom_set_serial_info(struct tty_struct *tty, if (reconfig_port) { unsigned long flags; spin_lock_irqsave(&port->card->card_lock, flags); - isicom_config_port(tty); + isicom_config_port(port); spin_unlock_irqrestore(&port->card->card_lock, flags); } unlock_kernel(); @@ -1319,7 +1318,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(tty, argp); + return isicom_set_serial_info(port, argp); default: return -ENOIOCTLCMD; @@ -1342,7 +1341,7 @@ static void isicom_set_termios(struct tty_struct *tty, return; spin_lock_irqsave(&port->card->card_lock, flags); - isicom_config_port(tty); + isicom_config_port(port); spin_unlock_irqrestore(&port->card->card_lock, flags); if ((old_termios->c_cflag & CRTSCTS) && @@ -1420,7 +1419,7 @@ static void isicom_hangup(struct tty_struct *tty) port->port.count = 0; port->port.flags &= ~ASYNC_NORMAL_ACTIVE; - tty_port_tty_set(&port->port, NULL); + port->port.tty = NULL; wake_up_interruptible(&port->port.open_wait); } diff --git a/trunk/drivers/char/istallion.c b/trunk/drivers/char/istallion.c index 505d7a1f6b8c..843a2afaf204 100644 --- a/trunk/drivers/char/istallion.c +++ b/trunk/drivers/char/istallion.c @@ -623,25 +623,24 @@ 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 tty_struct *tty, struct stlibrd *brdp, struct stliport *portp); +static int stli_initopen(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 tty_struct *tty, struct stlibrd *brdp, - struct stliport *portp, struct file *filp); -static int stli_setport(struct tty_struct *tty); +static int stli_waitcarrier(struct stlibrd *brdp, struct stliport *portp, struct file *filp); +static int stli_setport(struct stliport *portp); 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 tty_struct *tty, struct stliport *portp, asyport_t *pp, struct ktermios *tiosp); +static void stli_mkasyport(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 tty_struct *tty, struct serial_struct __user *sp); +static int stli_setserial(struct stliport *portp, struct serial_struct __user *sp); static int stli_getbrdstats(combrd_t __user *bp); -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_getportstats(struct stliport *portp, comstats_t __user *cp); +static int stli_portcmdstats(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); @@ -732,16 +731,12 @@ 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) { - tty = tty_port_tty_get(&portp->port); - if (tty != NULL) { - tty_hangup(tty); - tty_kref_put(tty); - } + if (portp->port.tty != NULL) + tty_hangup(portp->port.tty); kfree(portp); } } @@ -829,7 +824,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. */ - tty_port_tty_set(&portp->port, tty); + portp->port.tty = tty; tty->driver_data = portp; portp->port.count++; @@ -840,7 +835,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(tty, brdp, portp)) >= 0) { + if ((rc = stli_initopen(brdp, portp)) >= 0) { portp->port.flags |= ASYNC_INITIALIZED; clear_bit(TTY_IO_ERROR, &tty->flags); } @@ -869,7 +864,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(tty, brdp, portp, filp)) != 0) + if ((rc = stli_waitcarrier(brdp, portp, filp)) != 0) return rc; } portp->port.flags |= ASYNC_NORMAL_ACTIVE; @@ -935,7 +930,7 @@ static void stli_close(struct tty_struct *tty, struct file *filp) stli_flushbuffer(tty); tty->closing = 0; - tty_port_tty_set(&portp->port, NULL); + portp->port.tty = NULL; if (portp->openwaitcnt) { if (portp->close_delay) @@ -957,9 +952,9 @@ static void stli_close(struct tty_struct *tty, struct file *filp) * this still all happens pretty quickly. */ -static int stli_initopen(struct tty_struct *tty, - struct stlibrd *brdp, struct stliport *portp) +static int stli_initopen(struct stlibrd *brdp, struct stliport *portp) { + struct tty_struct *tty; asynotify_t nt; asyport_t aport; int rc; @@ -974,7 +969,10 @@ static int stli_initopen(struct tty_struct *tty, sizeof(asynotify_t), 0)) < 0) return rc; - stli_mkasyport(tty, portp, &aport, tty->termios); + tty = portp->port.tty; + if (tty == NULL) + return -ENODEV; + stli_mkasyport(portp, &aport, tty->termios); if ((rc = stli_cmdwait(brdp, portp, A_SETPORT, &aport, sizeof(asyport_t), 0)) < 0) return rc; @@ -1163,21 +1161,22 @@ 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 tty_struct *tty) +static int stli_setport(struct stliport *portp) { - 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(tty, portp, &aport, tty->termios); + stli_mkasyport(portp, &aport, portp->port.tty->termios); return(stli_cmdwait(brdp, portp, A_SETPORT, &aport, sizeof(asyport_t), 0)); } @@ -1188,8 +1187,7 @@ static int stli_setport(struct tty_struct *tty) * maybe because if we are clocal then we don't need to wait... */ -static int stli_waitcarrier(struct tty_struct *tty, struct stlibrd *brdp, - struct stliport *portp, struct file *filp) +static int stli_waitcarrier(struct stlibrd *brdp, struct stliport *portp, struct file *filp) { unsigned long flags; int rc, doclocal; @@ -1197,7 +1195,7 @@ static int stli_waitcarrier(struct tty_struct *tty, struct stlibrd *brdp, rc = 0; doclocal = 0; - if (tty->termios->c_cflag & CLOCAL) + if (portp->port.tty->termios->c_cflag & CLOCAL) doclocal++; spin_lock_irqsave(&stli_lock, flags); @@ -1375,6 +1373,8 @@ 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,11 +1572,10 @@ 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 tty_struct *tty, struct serial_struct __user *sp) +static int stli_setserial(struct stliport *portp, 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; @@ -1595,7 +1594,7 @@ static int stli_setserial(struct tty_struct *tty, struct serial_struct __user *s portp->closing_wait = sio.closing_wait; portp->custom_divisor = sio.custom_divisor; - if ((rc = stli_setport(tty)) < 0) + if ((rc = stli_setport(portp)) < 0) return rc; return 0; } @@ -1686,17 +1685,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(tty, argp); + rc = stli_setserial(portp, 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(tty); + stli_setport(portp); break; case COM_GETPORTSTATS: - rc = stli_getportstats(tty, portp, argp); + rc = stli_getportstats(portp, argp); break; case COM_CLRPORTSTATS: rc = stli_clrportstats(portp, argp); @@ -1730,6 +1729,8 @@ 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; @@ -1741,7 +1742,7 @@ static void stli_settermios(struct tty_struct *tty, struct ktermios *old) tiosp = tty->termios; - stli_mkasyport(tty, portp, &aport, tiosp); + stli_mkasyport(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, @@ -1853,7 +1854,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); - tty_port_tty_set(&portp->port, NULL); + portp->port.tty = NULL; portp->port.flags &= ~ASYNC_NORMAL_ACTIVE; portp->port.count = 0; spin_unlock_irqrestore(&stli_lock, flags); @@ -1934,6 +1935,8 @@ 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; @@ -1995,7 +1998,7 @@ static int stli_portinfo(struct stlibrd *brdp, struct stliport *portp, int portn char *sp, *uart; int rc, cnt; - rc = stli_portcmdstats(NULL, portp); + rc = stli_portcmdstats(portp); uart = "UNKNOWN"; if (brdp->state & BST_STARTED) { @@ -2185,7 +2188,7 @@ static void stli_read(struct stlibrd *brdp, struct stliport *portp) if (test_bit(ST_RXSTOP, &portp->state)) return; - tty = tty_port_tty_get(&portp->port); + tty = portp->port.tty; if (tty == NULL) return; @@ -2227,7 +2230,6 @@ static void stli_read(struct stlibrd *brdp, struct stliport *portp) set_bit(ST_RXING, &portp->state); tty_schedule_flip(tty); - tty_kref_put(tty); } /*****************************************************************************/ @@ -2360,7 +2362,7 @@ static int stli_hostcmd(struct stlibrd *brdp, struct stliport *portp) if (ap->notify) { nt = ap->changed; ap->notify = 0; - tty = tty_port_tty_get(&portp->port); + tty = portp->port.tty; if (nt.signal & SG_DCD) { oldsigs = portp->sigs; @@ -2397,7 +2399,6 @@ static int stli_hostcmd(struct stlibrd *brdp, struct stliport *portp) tty_schedule_flip(tty); } } - tty_kref_put(tty); if (nt.data & DT_RXBUSY) { donerx++; @@ -2534,15 +2535,14 @@ static void stli_poll(unsigned long arg) * the slave. */ -static void stli_mkasyport(struct tty_struct *tty, struct stliport *portp, - asyport_t *pp, struct ktermios *tiosp) +static void stli_mkasyport(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(tty); + pp->baudout = tty_get_baud_rate(portp->port.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 tty_struct *tty, struct stliport *portp) +static int stli_portcmdstats(struct stliport *portp) { unsigned long flags; struct stlibrd *brdp; @@ -4249,15 +4249,15 @@ static int stli_portcmdstats(struct tty_struct *tty, struct stliport *portp) stli_comstats.flags = portp->port.flags; spin_lock_irqsave(&brd_lock, flags); - if (tty != NULL) { - if (portp->port.tty == tty) { - stli_comstats.ttystate = tty->flags; + if (portp->port.tty != NULL) { + if (portp->port.tty->driver_data == portp) { + stli_comstats.ttystate = portp->port.tty->flags; stli_comstats.rxbuffered = -1; - 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; + 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; } } } @@ -4294,8 +4294,7 @@ static int stli_portcmdstats(struct tty_struct *tty, struct stliport *portp) * what port to get stats for (used through board control device). */ -static int stli_getportstats(struct tty_struct *tty, struct stliport *portp, - comstats_t __user *cp) +static int stli_getportstats(struct stliport *portp, comstats_t __user *cp) { struct stlibrd *brdp; int rc; @@ -4313,7 +4312,7 @@ static int stli_getportstats(struct tty_struct *tty, struct stliport *portp, if (!brdp) return -ENODEV; - if ((rc = stli_portcmdstats(tty, portp)) < 0) + if ((rc = stli_portcmdstats(portp)) < 0) return rc; return copy_to_user(cp, &stli_comstats, sizeof(comstats_t)) ? @@ -4428,7 +4427,7 @@ static int stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, un switch (cmd) { case COM_GETPORTSTATS: - rc = stli_getportstats(NULL, NULL, argp); + rc = stli_getportstats(NULL, argp); done++; break; case COM_CLRPORTSTATS: diff --git a/trunk/drivers/char/moxa.c b/trunk/drivers/char/moxa.c index 5df4003ad873..d3d7864e0c1e 100644 --- a/trunk/drivers/char/moxa.c +++ b/trunk/drivers/char/moxa.c @@ -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 tty_struct *); +static void moxa_shut_down(struct moxa_port *); /* * 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 tty_struct *, const unsigned char *, int); +static int MoxaPortWriteData(struct moxa_port *, const unsigned char *, int); static int MoxaPortReadData(struct moxa_port *); static int MoxaPortTxQueue(struct moxa_port *); static int MoxaPortRxQueue(struct moxa_port *); @@ -332,7 +332,6 @@ 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; @@ -345,12 +344,10 @@ static int moxa_ioctl(struct tty_struct *tty, struct file *file, if (status & 4) tmp.dcd = 1; - ttyp = tty_port_tty_get(&p->port); - if (!ttyp || !ttyp->termios) + if (!p->port.tty || !p->port.tty->termios) tmp.cflag = p->cflag; else - tmp.cflag = ttyp->termios->c_cflag; - tty_kref_put(tty); + tmp.cflag = p->port.tty->termios->c_cflag; copy: if (copy_to_user(argm, &tmp, sizeof(tmp))) { mutex_unlock(&moxa_openlock); @@ -883,14 +880,8 @@ 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) { - struct tty_struct *tty = tty_port_tty_get( - &brd->ports[a].port); - if (tty) { - tty_hangup(tty); - tty_kref_put(tty); - } - } + if (brd->ports[a].port.flags & ASYNC_INITIALIZED) + tty_hangup(brd->ports[a].port.tty); while (1) { opened = 0; for (a = 0; a < brd->numPorts; a++) @@ -1105,14 +1096,13 @@ static void __exit moxa_exit(void) module_init(moxa_init); module_exit(moxa_exit); -static void moxa_close_port(struct tty_struct *tty) +static void moxa_close_port(struct moxa_port *ch) { - struct moxa_port *ch = tty->driver_data; - moxa_shut_down(tty); + moxa_shut_down(ch); MoxaPortFlushData(ch, 2); ch->port.flags &= ~ASYNC_NORMAL_ACTIVE; - tty->driver_data = NULL; - tty_port_tty_set(&ch->port, NULL); + ch->port.tty->driver_data = NULL; + ch->port.tty = NULL; } static int moxa_block_till_ready(struct tty_struct *tty, struct file *filp, @@ -1171,7 +1161,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; - tty_port_tty_set(&ch->port, tty); + ch->port.tty = tty; if (!(ch->port.flags & ASYNC_INITIALIZED)) { ch->statusflags = 0; moxa_set_tty_param(tty, tty->termios); @@ -1189,7 +1179,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(tty); + moxa_close_port(ch); } else ch->port.flags |= ASYNC_NORMAL_ACTIVE; mutex_unlock(&moxa_openlock); @@ -1229,7 +1219,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(tty); + moxa_close_port(ch); unlock: mutex_unlock(&moxa_openlock); } @@ -1244,7 +1234,7 @@ static int moxa_write(struct tty_struct *tty, return 0; spin_lock_bh(&moxa_lock); - len = MoxaPortWriteData(tty, buf, count); + len = MoxaPortWriteData(ch, buf, count); spin_unlock_bh(&moxa_lock); ch->statusflags |= LOWWAIT; @@ -1419,7 +1409,7 @@ static void moxa_hangup(struct tty_struct *tty) return; } ch->port.count = 0; - moxa_close_port(tty); + moxa_close_port(ch); mutex_unlock(&moxa_openlock); wake_up_interruptible(&ch->port.open_wait); @@ -1427,14 +1417,11 @@ 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) { - tty = tty_port_tty_get(&p->port); - if (tty && C_CLOCAL(tty) && !dcd) - tty_hangup(tty); - tty_kref_put(tty); + if (dcd != p->DCDState && p->port.tty && C_CLOCAL(p->port.tty)) { + if (!dcd) + tty_hangup(p->port.tty); } p->DCDState = dcd; } @@ -1442,7 +1429,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 = tty_port_tty_get(&p->port); + struct tty_struct *tty = p->port.tty; void __iomem *ofsAddr; unsigned int inited = p->port.flags & ASYNC_INITIALIZED; u16 intr; @@ -1489,7 +1476,6 @@ 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); @@ -1574,9 +1560,9 @@ static void moxa_setup_empty_event(struct tty_struct *tty) spin_unlock_bh(&moxa_lock); } -static void moxa_shut_down(struct tty_struct *tty) +static void moxa_shut_down(struct moxa_port *ch) { - struct moxa_port *ch = tty->driver_data; + struct tty_struct *tp = ch->port.tty; if (!(ch->port.flags & ASYNC_INITIALIZED)) return; @@ -1586,7 +1572,7 @@ static void moxa_shut_down(struct tty_struct *tty) /* * If we're a modem control device and HUPCL is on, drop RTS & DTR. */ - if (C_HUPCL(tty)) + if (C_HUPCL(tp)) MoxaPortLineCtrl(ch, 0, 0); spin_lock_bh(&moxa_lock); @@ -1967,10 +1953,9 @@ static int MoxaPortLineStatus(struct moxa_port *port) return val; } -static int MoxaPortWriteData(struct tty_struct *tty, +static int MoxaPortWriteData(struct moxa_port *port, 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; diff --git a/trunk/drivers/char/mxser.c b/trunk/drivers/char/mxser.c index 8beef50f95a0..b638403e8e9c 100644 --- a/trunk/drivers/char/mxser.c +++ b/trunk/drivers/char/mxser.c @@ -610,13 +610,15 @@ static int mxser_block_til_ready(struct tty_struct *tty, struct file *filp, return 0; } -static int mxser_set_baud(struct tty_struct *tty, long newspd) +static int mxser_set_baud(struct mxser_port *info, long newspd) { - struct mxser_port *info = tty->driver_data; int quot = 0, baud; unsigned char cval; - if (!info->ioaddr) + if (!info->port.tty || !info->port.tty->termios) + return -1; + + if (!(info->ioaddr)) return -1; if (newspd > info->max_baud) @@ -624,13 +626,13 @@ static int mxser_set_baud(struct tty_struct *tty, long newspd) if (newspd == 134) { quot = 2 * info->baud_base / 269; - tty_encode_baud_rate(tty, 134, 134); + tty_encode_baud_rate(info->port.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(tty, baud, baud); + tty_encode_baud_rate(info->port.tty, baud, baud); } else { quot = 0; } @@ -656,7 +658,7 @@ static int mxser_set_baud(struct tty_struct *tty, long newspd) outb(cval, info->ioaddr + UART_LCR); /* reset DLAB */ #ifdef BOTHER - if (C_BAUD(tty) == BOTHER) { + if (C_BAUD(info->port.tty) == BOTHER) { quot = info->baud_base % newspd; quot *= 8; if (quot % newspd > newspd / 2) { @@ -677,20 +679,21 @@ static int mxser_set_baud(struct tty_struct *tty, 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 tty_struct *tty, - struct ktermios *old_termios) +static int mxser_change_speed(struct mxser_port *info, + struct ktermios *old_termios) { - struct mxser_port *info = tty->driver_data; unsigned cflag, cval, fcr; int ret = 0; unsigned char status; - cflag = tty->termios->c_cflag; - if (!info->ioaddr) + if (!info->port.tty || !info->port.tty->termios) + return ret; + cflag = info->port.tty->termios->c_cflag; + if (!(info->ioaddr)) return ret; - if (mxser_set_baud_method[tty->index] == 0) - mxser_set_baud(tty, tty_get_baud_rate(tty)); + if (mxser_set_baud_method[info->port.tty->index] == 0) + mxser_set_baud(info, tty_get_baud_rate(info->port.tty)); /* byte size and parity */ switch (cflag & CSIZE) { @@ -759,9 +762,9 @@ static int mxser_change_speed(struct tty_struct *tty, info->MCR |= UART_MCR_AFE; } else { status = inb(info->ioaddr + UART_MSR); - if (tty->hw_stopped) { + if (info->port.tty->hw_stopped) { if (status & UART_MSR_CTS) { - tty->hw_stopped = 0; + info->port.tty->hw_stopped = 0; if (info->type != PORT_16550A && !info->board->chip_flag) { outb(info->IER & ~UART_IER_THRI, @@ -771,11 +774,11 @@ static int mxser_change_speed(struct tty_struct *tty, outb(info->IER, info->ioaddr + UART_IER); } - tty_wakeup(tty); + tty_wakeup(info->port.tty); } } else { if (!(status & UART_MSR_CTS)) { - tty->hw_stopped = 1; + info->port.tty->hw_stopped = 1; if ((info->type != PORT_16550A) && (!info->board->chip_flag)) { info->IER &= ~UART_IER_THRI; @@ -801,21 +804,21 @@ static int mxser_change_speed(struct tty_struct *tty, * Set up parity check flag */ info->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; - if (I_INPCK(tty)) + if (I_INPCK(info->port.tty)) info->read_status_mask |= UART_LSR_FE | UART_LSR_PE; - if (I_BRKINT(tty) || I_PARMRK(tty)) + if (I_BRKINT(info->port.tty) || I_PARMRK(info->port.tty)) info->read_status_mask |= UART_LSR_BI; info->ignore_status_mask = 0; - if (I_IGNBRK(tty)) { + if (I_IGNBRK(info->port.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(tty)) { + if (I_IGNPAR(info->port.tty)) { info->ignore_status_mask |= UART_LSR_OE | UART_LSR_PE | @@ -827,16 +830,16 @@ static int mxser_change_speed(struct tty_struct *tty, } } if (info->board->chip_flag) { - 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_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_enable_must_rx_software_flow_control( info->ioaddr); } else { mxser_disable_must_rx_software_flow_control( info->ioaddr); } - if (I_IXOFF(tty)) { + if (I_IXOFF(info->port.tty)) { mxser_enable_must_tx_software_flow_control( info->ioaddr); } else { @@ -852,8 +855,7 @@ static int mxser_change_speed(struct tty_struct *tty, return ret; } -static void mxser_check_modem_status(struct tty_struct *tty, - struct mxser_port *port, int status) +static void mxser_check_modem_status(struct mxser_port *port, int status) { /* update input line counters */ if (status & UART_MSR_TERI) @@ -872,11 +874,10 @@ static void mxser_check_modem_status(struct tty_struct *tty, wake_up_interruptible(&port->port.open_wait); } - tty = tty_port_tty_get(&port->port); if (port->port.flags & ASYNC_CTS_FLOW) { - if (tty->hw_stopped) { + if (port->port.tty->hw_stopped) { if (status & UART_MSR_CTS) { - tty->hw_stopped = 0; + port->port.tty->hw_stopped = 0; if ((port->type != PORT_16550A) && (!port->board->chip_flag)) { @@ -886,11 +887,11 @@ static void mxser_check_modem_status(struct tty_struct *tty, outb(port->IER, port->ioaddr + UART_IER); } - tty_wakeup(tty); + tty_wakeup(port->port.tty); } } else { if (!(status & UART_MSR_CTS)) { - tty->hw_stopped = 1; + port->port.tty->hw_stopped = 1; if (port->type != PORT_16550A && !port->board->chip_flag) { port->IER &= ~UART_IER_THRI; @@ -902,9 +903,8 @@ static void mxser_check_modem_status(struct tty_struct *tty, } } -static int mxser_startup(struct tty_struct *tty) +static int mxser_startup(struct mxser_port *info) { - struct mxser_port *info = tty->driver_data; unsigned long page; unsigned long flags; @@ -921,7 +921,8 @@ static int mxser_startup(struct tty_struct *tty) } if (!info->ioaddr || !info->type) { - set_bit(TTY_IO_ERROR, &tty->flags); + if (info->port.tty) + set_bit(TTY_IO_ERROR, &info->port.tty->flags); free_page(page); spin_unlock_irqrestore(&info->slock, flags); return 0; @@ -951,8 +952,8 @@ static int mxser_startup(struct tty_struct *tty) if (inb(info->ioaddr + UART_LSR) == 0xff) { spin_unlock_irqrestore(&info->slock, flags); if (capable(CAP_SYS_ADMIN)) { - if (tty) - set_bit(TTY_IO_ERROR, &tty->flags); + if (info->port.tty) + set_bit(TTY_IO_ERROR, &info->port.tty->flags); return 0; } else return -ENODEV; @@ -990,13 +991,14 @@ static int mxser_startup(struct tty_struct *tty) (void) inb(info->ioaddr + UART_IIR); (void) inb(info->ioaddr + UART_MSR); - clear_bit(TTY_IO_ERROR, &tty->flags); + 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 */ - mxser_change_speed(tty, NULL); + mxser_change_speed(info, NULL); info->port.flags |= ASYNC_INITIALIZED; spin_unlock_irqrestore(&info->slock, flags); @@ -1007,9 +1009,8 @@ static int mxser_startup(struct tty_struct *tty) * 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 tty_struct *tty) +static void mxser_shutdown(struct mxser_port *info) { - struct mxser_port *info = tty->driver_data; unsigned long flags; if (!(info->port.flags & ASYNC_INITIALIZED)) @@ -1034,7 +1035,7 @@ static void mxser_shutdown(struct tty_struct *tty) info->IER = 0; outb(0x00, info->ioaddr + UART_IER); - if (tty->termios->c_cflag & HUPCL) + if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL)) info->MCR &= ~(UART_MCR_DTR | UART_MCR_RTS); outb(info->MCR, info->ioaddr + UART_MCR); @@ -1050,7 +1051,8 @@ static void mxser_shutdown(struct tty_struct *tty) /* read data port to reset things */ (void) inb(info->ioaddr + UART_RX); - set_bit(TTY_IO_ERROR, &tty->flags); + if (info->port.tty) + set_bit(TTY_IO_ERROR, &info->port.tty->flags); info->port.flags &= ~ASYNC_INITIALIZED; @@ -1082,14 +1084,14 @@ static int mxser_open(struct tty_struct *tty, struct file *filp) return -ENODEV; tty->driver_data = info; - tty_port_tty_set(&info->port, tty); + info->port.tty = tty; /* * Start up serial port */ spin_lock_irqsave(&info->slock, flags); info->port.count++; spin_unlock_irqrestore(&info->slock, flags); - retval = mxser_startup(tty); + retval = mxser_startup(info); if (retval) return retval; @@ -1207,13 +1209,13 @@ static void mxser_close(struct tty_struct *tty, struct file *filp) break; } } - mxser_shutdown(tty); + mxser_shutdown(info); mxser_flush_buffer(tty); tty_ldisc_flush(tty); tty->closing = 0; - tty_port_tty_set(&info->port, NULL); + info->port.tty = NULL; if (info->port.blocked_open) { if (info->port.close_delay) schedule_timeout_interruptible(info->port.close_delay); @@ -1335,13 +1337,12 @@ static int mxser_chars_in_buffer(struct tty_struct *tty) * friends of mxser_ioctl() * ------------------------------------------------------------ */ -static int mxser_get_serial_info(struct tty_struct *tty, +static int mxser_get_serial_info(struct mxser_port *info, struct serial_struct __user *retinfo) { - struct mxser_port *info = tty->driver_data; struct serial_struct tmp = { .type = info->type, - .line = tty->index, + .line = info->port.tty->index, .port = info->ioaddr, .irq = info->board->irq, .flags = info->port.flags, @@ -1356,10 +1357,9 @@ static int mxser_get_serial_info(struct tty_struct *tty, return 0; } -static int mxser_set_serial_info(struct tty_struct *tty, +static int mxser_set_serial_info(struct mxser_port *info, 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 tty_struct *tty, (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; - tty->low_latency = (info->port.flags & ASYNC_LOW_LATENCY) - ? 1 : 0; + info->port.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(tty, baud, baud); + tty_encode_baud_rate(info->port.tty, baud, baud); } } @@ -1411,11 +1411,11 @@ static int mxser_set_serial_info(struct tty_struct *tty, if (info->port.flags & ASYNC_INITIALIZED) { if (flags != (info->port.flags & ASYNC_SPD_MASK)) { spin_lock_irqsave(&info->slock, sl_flags); - mxser_change_speed(tty, NULL); + mxser_change_speed(info, NULL); spin_unlock_irqrestore(&info->slock, sl_flags); } } else - retval = mxser_startup(tty); + retval = mxser_startup(info); 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(tty, info, status); + mxser_check_modem_status(info, status); spin_unlock_irqrestore(&info->slock, flags); return ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) | ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) | @@ -1606,7 +1606,6 @@ 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; @@ -1644,14 +1643,12 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp) if (!port->ioaddr) goto copy; - - tty = tty_port_tty_get(&port->port); - if (!tty || !tty->termios) + if (!port->port.tty || !port->port.tty->termios) ms.cflag = port->normal_termios.c_cflag; else - ms.cflag = tty->termios->c_cflag; - tty_kref_put(tty); + ms.cflag = port->port.tty->termios->c_cflag; + status = inb(port->ioaddr + UART_MSR); if (status & UART_MSR_DCD) ms.dcd = 1; @@ -1707,18 +1704,15 @@ 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; - tty = tty_port_tty_get(&port->port); + me->baudrate[p] = tty_get_baud_rate(port->port.tty); - if (!tty || !tty->termios) { + if (!port->port.tty || !port->port.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 = tty->termios->c_cflag; - iflag = tty->termios->c_iflag; - me->baudrate[p] = tty_get_baud_rate(tty); + cflag = port->port.tty->termios->c_cflag; + iflag = port->port.tty->termios->c_iflag; } - tty_kref_put(tty); me->databits[p] = cflag & CSIZE; me->stopbits[p] = cflag & CSTOPB; @@ -1828,12 +1822,12 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file, switch (cmd) { case TIOCGSERIAL: lock_kernel(); - retval = mxser_get_serial_info(tty, argp); + retval = mxser_get_serial_info(info, argp); unlock_kernel(); return retval; case TIOCSSERIAL: lock_kernel(); - retval = mxser_set_serial_info(tty, argp); + retval = mxser_set_serial_info(info, argp); unlock_kernel(); return retval; case TIOCSERGETLSR: /* Get line status register */ @@ -1902,7 +1896,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(tty, info, status); + mxser_check_modem_status(info, status); mcr = inb(info->ioaddr + UART_MCR); if (mcr & MOXA_MUST_MCR_XON_FLAG) @@ -1915,7 +1909,7 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file, else info->mon_data.hold_reason |= NPPI_NOTIFY_XOFFXENT; - if (tty->hw_stopped) + if (info->port.tty->hw_stopped) info->mon_data.hold_reason |= NPPI_NOTIFY_CTSHOLD; else info->mon_data.hold_reason &= ~NPPI_NOTIFY_CTSHOLD; @@ -1964,7 +1958,7 @@ static void mxser_stoprx(struct tty_struct *tty) } } - if (tty->termios->c_cflag & CRTSCTS) { + if (info->port.tty->termios->c_cflag & CRTSCTS) { info->MCR &= ~UART_MCR_RTS; outb(info->MCR, info->ioaddr + UART_MCR); } @@ -2001,7 +1995,7 @@ static void mxser_unthrottle(struct tty_struct *tty) } } - if (tty->termios->c_cflag & CRTSCTS) { + if (info->port.tty->termios->c_cflag & CRTSCTS) { info->MCR |= UART_MCR_RTS; outb(info->MCR, info->ioaddr + UART_MCR); } @@ -2046,7 +2040,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(tty, old_termios); + mxser_change_speed(info, old_termios); spin_unlock_irqrestore(&info->slock, flags); if ((old_termios->c_cflag & CRTSCTS) && @@ -2144,10 +2138,10 @@ static void mxser_hangup(struct tty_struct *tty) struct mxser_port *info = tty->driver_data; mxser_flush_buffer(tty); - mxser_shutdown(tty); + mxser_shutdown(info); info->port.count = 0; info->port.flags &= ~ASYNC_NORMAL_ACTIVE; - tty_port_tty_set(&info->port, NULL); + info->port.tty = NULL; wake_up_interruptible(&info->port.open_wait); } @@ -2170,9 +2164,9 @@ static int mxser_rs_break(struct tty_struct *tty, int break_state) return 0; } -static void mxser_receive_chars(struct tty_struct *tty, - struct mxser_port *port, int *status) +static void mxser_receive_chars(struct mxser_port *port, int *status) { + struct tty_struct *tty = port->port.tty; unsigned char ch, gdl; int ignored = 0; int cnt = 0; @@ -2180,8 +2174,9 @@ static void mxser_receive_chars(struct tty_struct *tty, 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) @@ -2258,7 +2253,7 @@ static void mxser_receive_chars(struct tty_struct *tty, } while (*status & UART_LSR_DR); end_intr: - mxvar_log.rxcnt[tty->index] += cnt; + mxvar_log.rxcnt[port->port.tty->index] += cnt; port->mon_data.rxcnt += cnt; port->mon_data.up_rxcnt += cnt; @@ -2272,14 +2267,14 @@ static void mxser_receive_chars(struct tty_struct *tty, spin_lock(&port->slock); } -static void mxser_transmit_chars(struct tty_struct *tty, struct mxser_port *port) +static void mxser_transmit_chars(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[tty->index]++; + mxvar_log.txcnt[port->port.tty->index]++; port->mon_data.txcnt++; port->mon_data.up_txcnt++; port->icount.tx++; @@ -2289,8 +2284,8 @@ static void mxser_transmit_chars(struct tty_struct *tty, struct mxser_port *port if (port->port.xmit_buf == NULL) return; - if (port->xmit_cnt <= 0 || tty->stopped || - (tty->hw_stopped && + if ((port->xmit_cnt <= 0) || port->port.tty->stopped || + (port->port.tty->hw_stopped && (port->type != PORT_16550A) && (!port->board->chip_flag))) { port->IER &= ~UART_IER_THRI; @@ -2307,14 +2302,14 @@ static void mxser_transmit_chars(struct tty_struct *tty, struct mxser_port *port if (--port->xmit_cnt <= 0) break; } while (--count > 0); - mxvar_log.txcnt[tty->index] += (cnt - port->xmit_cnt); + mxvar_log.txcnt[port->port.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) - tty_wakeup(tty); + if (port->xmit_cnt < WAKEUP_CHARS) + tty_wakeup(port->port.tty); if (port->xmit_cnt <= 0) { port->IER &= ~UART_IER_THRI; @@ -2333,7 +2328,6 @@ 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]) { @@ -2366,15 +2360,13 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id) if (iir & UART_IIR_NO_INT) break; iir &= MOXA_MUST_IIR_MASK; - tty = tty_port_tty_get(&port->port); - if (!tty || + if (!port->port.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; } @@ -2395,28 +2387,27 @@ 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(tty, port, + mxser_receive_chars(port, &status); } else { status &= port->read_status_mask; if (status & UART_LSR_DR) - mxser_receive_chars(tty, port, + mxser_receive_chars(port, &status); } msr = inb(port->ioaddr + UART_MSR); if (msr & UART_MSR_ANY_DELTA) - mxser_check_modem_status(tty, port, msr); + mxser_check_modem_status(port, msr); if (port->board->chip_flag) { if (iir == 0x02 && (status & UART_LSR_THRE)) - mxser_transmit_chars(tty, port); + mxser_transmit_chars(port); } else { if (status & UART_LSR_THRE) - mxser_transmit_chars(tty, port); + mxser_transmit_chars(port); } - tty_kref_put(tty); } while (int_cnt++ < MXSER_ISR_PASS_LIMIT); spin_unlock(&port->slock); } diff --git a/trunk/drivers/char/n_hdlc.c b/trunk/drivers/char/n_hdlc.c index bacb3e2872ae..69ec6399c714 100644 --- a/trunk/drivers/char/n_hdlc.c +++ b/trunk/drivers/char/n_hdlc.c @@ -764,7 +764,7 @@ static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file, break; default: - error = n_tty_ioctl_helper(tty, file, cmd, arg); + error = n_tty_ioctl (tty, file, cmd, arg); break; } return error; diff --git a/trunk/drivers/char/n_r3964.c b/trunk/drivers/char/n_r3964.c index 4a8215a89ad3..ae377aa473ba 100644 --- a/trunk/drivers/char/n_r3964.c +++ b/trunk/drivers/char/n_r3964.c @@ -372,8 +372,14 @@ 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 */ - tty_put_char(tty, ch); + if (tty->ops->put_char) { + tty->ops->put_char(tty, ch); + } pInfo->bcc ^= ch; } diff --git a/trunk/drivers/char/n_tty.c b/trunk/drivers/char/n_tty.c index efbfe9612658..708c2b1dbe51 100644 --- a/trunk/drivers/char/n_tty.c +++ b/trunk/drivers/char/n_tty.c @@ -26,7 +26,7 @@ * * 2002/03/18 Implemented n_tty_wakeup to send SIGIO POLL_OUTs to * waiting writing processes-Sapan Bhatia . - * Also fixed a bug in BLOCKING mode where n_tty_write returns + * Also fixed a bug in BLOCKING mode where write_chan returns * EAGAIN */ @@ -99,7 +99,6 @@ 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; /* @@ -122,16 +121,6 @@ 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; @@ -148,11 +137,14 @@ 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 functions - * + * 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. * 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) @@ -166,8 +158,6 @@ 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) { @@ -191,7 +181,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, read_lock. + * Locking: ctrl_lock */ static void n_tty_flush_buffer(struct tty_struct *tty) @@ -217,8 +207,6 @@ 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) @@ -358,7 +346,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 n_tty_write under the tty layer write lock. Relies + * Called from write_chan under the tty layer write lock. Relies * on lock_kernel for the tty->column state. */ @@ -422,8 +410,6 @@ static ssize_t opost_block(struct tty_struct *tty, * * 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) @@ -436,12 +422,6 @@ 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) { @@ -459,8 +439,6 @@ 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) @@ -469,7 +447,6 @@ 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; @@ -504,7 +481,6 @@ 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; @@ -607,8 +583,6 @@ 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) @@ -1033,26 +1007,12 @@ 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) { - 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); + if (!tty) + return; tty->icanon = (L_ICANON(tty) != 0); if (test_bit(TTY_HW_COOK_IN, &tty->flags)) { @@ -1183,7 +1143,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 n_tty_read. It is only called when + * Helper function to speed up read_chan. 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 @@ -1250,7 +1210,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 "n_tty_read: no tty->pgrp!\n"); + printk(KERN_ERR "read_chan: no tty->pgrp!\n"); else if (task_pgrp(current) != tty->pgrp) { if (is_ignored(SIGTTIN) || is_current_pgrp_orphaned()) @@ -1265,7 +1225,7 @@ static int job_control(struct tty_struct *tty, struct file *file) /** - * n_tty_read - read function for tty + * read_chan - read function for tty * @tty: tty device * @file: file object * @buf: userspace buffer pointer @@ -1279,7 +1239,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 n_tty_read(struct tty_struct *tty, struct file *file, +static ssize_t read_chan(struct tty_struct *tty, struct file *file, unsigned char __user *buf, size_t nr) { unsigned char __user *b = buf; @@ -1294,7 +1254,10 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, do_it_again: - BUG_ON(!tty->read_buf); + if (!tty->read_buf) { + printk(KERN_ERR "n_tty_read_chan: read_buf == NULL?!?\n"); + return -EIO; + } c = job_control(tty, file); if (c < 0) @@ -1481,7 +1444,7 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, } /** - * n_tty_write - write function for tty + * write_chan - write function for tty * @tty: tty device * @file: file object * @buf: userspace buffer pointer @@ -1495,7 +1458,7 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, * This code must be sure never to sleep through a hangup. */ -static ssize_t n_tty_write(struct tty_struct *tty, struct file *file, +static ssize_t write_chan(struct tty_struct *tty, struct file *file, const unsigned char *buf, size_t nr) { const unsigned char *b = buf; @@ -1569,7 +1532,7 @@ static ssize_t n_tty_write(struct tty_struct *tty, struct file *file, } /** - * n_tty_poll - poll method for N_TTY + * normal_poll - poll method for N_TTY * @tty: terminal device * @file: file accessing it * @wait: poll table @@ -1582,7 +1545,7 @@ static ssize_t n_tty_write(struct tty_struct *tty, struct file *file, * Called without the kernel lock held - fine */ -static unsigned int n_tty_poll(struct tty_struct *tty, struct file *file, +static unsigned int normal_poll(struct tty_struct *tty, struct file *file, poll_table *wait) { unsigned int mask = 0; @@ -1610,44 +1573,6 @@ static unsigned int n_tty_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", @@ -1655,11 +1580,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 = n_tty_read, - .write = n_tty_write, + .read = read_chan, + .write = write_chan, .ioctl = n_tty_ioctl, .set_termios = n_tty_set_termios, - .poll = n_tty_poll, + .poll = normal_poll, .receive_buf = n_tty_receive_buf, .write_wakeup = n_tty_write_wakeup }; diff --git a/trunk/drivers/char/nozomi.c b/trunk/drivers/char/nozomi.c index 9a34a1935283..66a0f931c66c 100644 --- a/trunk/drivers/char/nozomi.c +++ b/trunk/drivers/char/nozomi.c @@ -1599,10 +1599,7 @@ static int ntty_open(struct tty_struct *tty, struct file *file) return 0; } -/* 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 */ - +/* Called when the userspace process close the tty, /dev/noz*. */ static void ntty_close(struct tty_struct *tty, struct file *file) { struct nozomi *dc = get_dc_by_tty(tty); diff --git a/trunk/drivers/char/pcmcia/ipwireless/tty.c b/trunk/drivers/char/pcmcia/ipwireless/tty.c index 569f2f7743a7..3a23e7694d55 100644 --- a/trunk/drivers/char/pcmcia/ipwireless/tty.c +++ b/trunk/drivers/char/pcmcia/ipwireless/tty.c @@ -276,7 +276,6 @@ 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; @@ -398,7 +397,6 @@ 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; @@ -414,7 +412,6 @@ 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; @@ -436,8 +433,6 @@ 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); @@ -472,6 +467,13 @@ 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; @@ -480,11 +482,10 @@ 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 tty_mode_ioctl(linux_tty, file, cmd , arg); + + return -ENOIOCTLCMD; } static int add_tty(dev_node_t *nodesp, int j, @@ -587,8 +588,6 @@ 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) diff --git a/trunk/drivers/char/pty.c b/trunk/drivers/char/pty.c index 6d4582712b1f..76b27932d229 100644 --- a/trunk/drivers/char/pty.c +++ b/trunk/drivers/char/pty.c @@ -8,12 +8,10 @@ * Added TTY_DO_WRITE_WAKEUP to enable n_tty to send POLL_OUT to * waiting writers -- Sapan Bhatia * - * 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 +#include /* For EXPORT_SYMBOL */ #include #include @@ -25,12 +23,11 @@ #include #include #include -#include -#include -#include -#include +#include #include +#include +#include /* These are global because they are accessed in tty_io.c */ #ifdef CONFIG_UNIX98_PTYS @@ -38,12 +35,14 @@ 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) { - BUG_ON(!tty); - if (tty->driver->subtype == PTY_TYPE_MASTER) - WARN_ON(tty->count > 1); - else { + if (!tty) + return; + if (tty->driver->subtype == PTY_TYPE_MASTER) { + if (tty->count > 1) + printk("master pty_close: count = %d!!\n", tty->count); + } else { if (tty->count > 2) return; } @@ -60,7 +59,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->link); + devpts_pty_kill(tty->index); #endif tty_vhangup(tty->link); } @@ -70,13 +69,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; @@ -88,7 +87,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 @@ -101,8 +100,7 @@ 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; @@ -114,7 +112,7 @@ static int pty_write(struct tty_struct *tty, const unsigned char *buf, if (c > count) c = count; to->ldisc.ops->receive_buf(to, buf, NULL, c); - + return c; } @@ -130,17 +128,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. @@ -157,22 +155,21 @@ 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); @@ -185,13 +182,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; @@ -200,7 +197,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; @@ -223,65 +220,13 @@ static int pty_open(struct tty_struct *tty, struct file *filp) return retval; } -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) +static void pty_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { - 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; + tty->termios->c_cflag &= ~(CSIZE | PARENB); + tty->termios->c_cflag |= (CS8 | CREAD); } - static const struct tty_operations pty_ops = { - .install = pty_install, .open = pty_open, .close = pty_close, .write = pty_write, @@ -384,11 +329,8 @@ 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; +static int pty_limit_min = 0; static int pty_limit_max = NR_UNIX98_PTY_MAX; -static int pty_count; - -static struct cdev ptmx_cdev; static struct ctl_table pty_table[] = { { @@ -406,7 +348,6 @@ static struct ctl_table pty_table[] = { .procname = "nr", .maxlen = sizeof(int), .mode = 0444, - .data = &pty_count, .proc_handler = &proc_dointvec, }, { .ctl_name = 0 @@ -447,127 +388,7 @@ 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, @@ -576,73 +397,9 @@ static const struct tty_operations pty_unix98_ops = { .chars_in_buffer = pty_chars_in_buffer, .unthrottle = pty_unthrottle, .set_termios = pty_set_termios, - .shutdown = pty_unix98_shutdown + .ioctl = pty_unix98_ioctl }; -/** - * 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) { @@ -670,7 +427,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, &ptm_unix98_ops); + tty_set_operations(ptm_driver, &pty_unix98_ops); pts_driver->owner = THIS_MODULE; pts_driver->driver_name = "pty_slave"; @@ -686,26 +443,16 @@ 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_unix98_ops); - + tty_set_operations(pts_driver, &pty_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 diff --git a/trunk/drivers/char/stallion.c b/trunk/drivers/char/stallion.c index 8b8f07a7f505..19db1eb87c26 100644 --- a/trunk/drivers/char/stallion.c +++ b/trunk/drivers/char/stallion.c @@ -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 tty_struct *tty, struct stlport *portp, comstats_t __user *cp); +static int stl_getportstats(struct stlport *portp, comstats_t __user *cp); static int stl_clrportstats(struct stlport *portp, comstats_t __user *cp); -static int stl_waitcarrier(struct tty_struct *tty, struct stlport *portp, struct file *filp); +static int stl_waitcarrier(struct stlport *portp, struct file *filp); /* * CD1400 uart specific handling functions. @@ -612,9 +612,8 @@ 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 (!tty) + if (!portp->port.tty) return; portp->sigs = stl_getsignals(portp); @@ -624,8 +623,7 @@ 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(tty); - tty_kref_put(tty); + tty_hangup(portp->port.tty); } /* @@ -736,7 +734,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. */ - tty_port_tty_set(&portp->port, tty); + portp->port.tty = tty; tty->driver_data = portp; portp->port.count++; @@ -776,7 +774,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(tty, portp, filp)) != 0) + if ((rc = stl_waitcarrier(portp, filp)) != 0) return rc; portp->port.flags |= ASYNC_NORMAL_ACTIVE; @@ -791,8 +789,7 @@ 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 tty_struct *tty, struct stlport *portp, - struct file *filp) +static int stl_waitcarrier(struct stlport *portp, struct file *filp) { unsigned long flags; int rc, doclocal; @@ -804,7 +801,7 @@ static int stl_waitcarrier(struct tty_struct *tty, struct stlport *portp, spin_lock_irqsave(&stallion_lock, flags); - if (tty->termios->c_cflag & CLOCAL) + if (portp->port.tty->termios->c_cflag & CLOCAL) doclocal++; portp->openwaitcnt++; @@ -849,6 +846,8 @@ 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; @@ -866,6 +865,8 @@ 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; @@ -948,7 +949,7 @@ static void stl_close(struct tty_struct *tty, struct file *filp) tty_ldisc_flush(tty); tty->closing = 0; - tty_port_tty_set(&portp->port, NULL); + portp->port.tty = NULL; if (portp->openwaitcnt) { if (portp->close_delay) @@ -1032,6 +1033,8 @@ 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; @@ -1067,6 +1070,8 @@ 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; @@ -1085,6 +1090,8 @@ 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; @@ -1115,6 +1122,8 @@ 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; @@ -1174,9 +1183,8 @@ 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 tty_struct *tty, struct serial_struct __user *sp) +static int stl_setserial(struct stlport *portp, 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); @@ -1197,7 +1205,7 @@ static int stl_setserial(struct tty_struct *tty, 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, tty->termios); + stl_setport(portp, portp->port.tty->termios); return 0; } @@ -1207,6 +1215,8 @@ 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; @@ -1222,6 +1232,8 @@ 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; @@ -1250,6 +1262,8 @@ 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; @@ -1268,10 +1282,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(tty, argp); + rc = stl_setserial(portp, argp); break; case COM_GETPORTSTATS: - rc = stl_getportstats(tty, portp, argp); + rc = stl_getportstats(portp, argp); break; case COM_CLRPORTSTATS: rc = stl_clrportstats(portp, argp); @@ -1303,6 +1317,8 @@ 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; @@ -1318,6 +1334,8 @@ 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; @@ -1351,6 +1369,8 @@ 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; @@ -1369,6 +1389,8 @@ 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; @@ -1388,6 +1410,8 @@ 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; @@ -1408,6 +1432,8 @@ 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; @@ -1426,7 +1452,7 @@ static void stl_hangup(struct tty_struct *tty) portp->tx.head = NULL; portp->tx.tail = NULL; } - tty_port_tty_set(&portp->port, NULL); + portp->port.tty = NULL; portp->port.flags &= ~ASYNC_NORMAL_ACTIVE; portp->port.count = 0; wake_up_interruptible(&portp->port.open_wait); @@ -1440,6 +1466,8 @@ 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; @@ -1456,6 +1484,8 @@ 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; @@ -1775,7 +1805,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; @@ -1802,7 +1832,6 @@ 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]; @@ -1812,11 +1841,8 @@ static void stl_cleanup_panels(struct stlbrd *brdp) portp = panelp->ports[k]; if (portp == NULL) continue; - tty = tty_port_tty_get(&portp->port); - if (tty != NULL) { - stl_hangup(tty); - tty_kref_put(tty); - } + if (portp->port.tty != NULL) + stl_hangup(portp->port.tty); kfree(portp->tx.buf); kfree(portp); } @@ -2472,7 +2498,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 tty_struct *tty, struct stlport *portp, comstats_t __user *cp) +static int stl_getportstats(struct stlport *portp, comstats_t __user *cp) { comstats_t stl_comstats; unsigned char *head, *tail; @@ -2499,17 +2525,18 @@ static int stl_getportstats(struct tty_struct *tty, struct stlport *portp, comst portp->stats.rxbuffered = 0; spin_lock_irqsave(&stallion_lock, flags); - 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; + 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; + } } - } spin_unlock_irqrestore(&stallion_lock, flags); head = portp->tx.head; @@ -2613,7 +2640,7 @@ static int stl_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, uns switch (cmd) { case COM_GETPORTSTATS: - rc = stl_getportstats(NULL, NULL, argp); + rc = stl_getportstats(NULL, argp); break; case COM_CLRPORTSTATS: rc = stl_clrportstats(NULL, argp); @@ -3216,7 +3243,7 @@ static void stl_cd1400flowctrl(struct stlport *portp, int state) if (portp == NULL) return; - tty = tty_port_tty_get(&portp->port); + tty = portp->port.tty; if (tty == NULL) return; @@ -3261,7 +3288,6 @@ static void stl_cd1400flowctrl(struct stlport *portp, int state) BRDDISABLE(portp->brdnr); spin_unlock_irqrestore(&brd_lock, flags); - tty_kref_put(tty); } /*****************************************************************************/ @@ -3279,7 +3305,7 @@ static void stl_cd1400sendflow(struct stlport *portp, int state) if (portp == NULL) return; - tty = tty_port_tty_get(&portp->port); + tty = portp->port.tty; if (tty == NULL) return; @@ -3299,7 +3325,6 @@ static void stl_cd1400sendflow(struct stlport *portp, int state) } BRDDISABLE(portp->brdnr); spin_unlock_irqrestore(&brd_lock, flags); - tty_kref_put(tty); } /*****************************************************************************/ @@ -3453,7 +3478,6 @@ 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); @@ -3480,11 +3504,8 @@ 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); - tty = tty_port_tty_get(&portp->port); - if (tty) { - tty_wakeup(tty); - tty_kref_put(tty); - } + if (portp->port.tty) + tty_wakeup(portp->port.tty); } if (len == 0) { @@ -3548,7 +3569,7 @@ static void stl_cd1400rxisr(struct stlpanel *panelp, int ioaddr) return; } portp = panelp->ports[(ioack >> 3)]; - tty = tty_port_tty_get(&portp->port); + tty = portp->port.tty; if ((ioack & ACK_TYPMASK) == ACK_TYPRXGOOD) { outb((RDCR + portp->uartaddr), ioaddr); @@ -3612,12 +3633,10 @@ 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)); } @@ -4156,7 +4175,7 @@ static void stl_sc26198flowctrl(struct stlport *portp, int state) if (portp == NULL) return; - tty = tty_port_tty_get(&portp->port); + tty = portp->port.tty; if (tty == NULL) return; @@ -4207,7 +4226,6 @@ static void stl_sc26198flowctrl(struct stlport *portp, int state) BRDDISABLE(portp->brdnr); spin_unlock_irqrestore(&brd_lock, flags); - tty_kref_put(tty); } /*****************************************************************************/ @@ -4226,7 +4244,7 @@ static void stl_sc26198sendflow(struct stlport *portp, int state) if (portp == NULL) return; - tty = tty_port_tty_get(&portp->port); + tty = portp->port.tty; if (tty == NULL) return; @@ -4251,7 +4269,6 @@ static void stl_sc26198sendflow(struct stlport *portp, int state) } BRDDISABLE(portp->brdnr); spin_unlock_irqrestore(&brd_lock, flags); - tty_kref_put(tty); } /*****************************************************************************/ @@ -4391,7 +4408,6 @@ 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; @@ -4406,11 +4422,8 @@ 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); - tty = tty_port_tty_get(&portp->port); - if (tty) { - tty_wakeup(tty); - tty_kref_put(tty); - } + if (portp->port.tty) + tty_wakeup(portp->port.tty); } if (len == 0) { @@ -4463,7 +4476,7 @@ static void stl_sc26198rxisr(struct stlport *portp, unsigned int iack) pr_debug("stl_sc26198rxisr(portp=%p,iack=%x)\n", portp, iack); - tty = tty_port_tty_get(&portp->port); + tty = portp->port.tty; ioaddr = portp->ioaddr; outb(GIBCR, (ioaddr + XP_ADDR)); len = inb(ioaddr + XP_DATA) + 1; @@ -4502,7 +4515,6 @@ static void stl_sc26198rxisr(struct stlport *portp, unsigned int iack) stl_sc26198txunflow(portp, tty); } } - tty_kref_put(tty); } /*****************************************************************************/ @@ -4516,7 +4528,7 @@ static void stl_sc26198rxbadch(struct stlport *portp, unsigned char status, char struct tty_struct *tty; unsigned int ioaddr; - tty = tty_port_tty_get(&portp->port); + tty = portp->port.tty; ioaddr = portp->ioaddr; if (status & SR_RXPARITY) @@ -4554,7 +4566,6 @@ static void stl_sc26198rxbadch(struct stlport *portp, unsigned char status, char if (status == 0) portp->stats.rxtotal++; } - tty_kref_put(tty); } /*****************************************************************************/ diff --git a/trunk/drivers/char/sx.c b/trunk/drivers/char/sx.c index 5b8d7a1aa3e6..c385206f9db5 100644 --- a/trunk/drivers/char/sx.c +++ b/trunk/drivers/char/sx.c @@ -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->base2); + pci_iounmap(pdev, board->base); 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->base2); + pci_iounmap(pdev, board->base); err_reg: pci_release_region(pdev, reg); err_flag: diff --git a/trunk/drivers/char/tpm/tpm.c b/trunk/drivers/char/tpm/tpm.c index 1fee7034a386..ae766d868454 100644 --- a/trunk/drivers/char/tpm/tpm.c +++ b/trunk/drivers/char/tpm/tpm.c @@ -954,63 +954,72 @@ 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 minor = iminor(inode); + int rc = 0, minor = iminor(inode); struct tpm_chip *chip = NULL, *pos; - rcu_read_lock(); - list_for_each_entry_rcu(pos, &tpm_chip_list, list) { + lock_kernel(); + spin_lock(&driver_lock); + + list_for_each_entry(pos, &tpm_chip_list, list) { if (pos->vendor.miscdev.minor == minor) { chip = pos; - get_device(chip->dev); break; } } - rcu_read_unlock(); - if (!chip) - return -ENODEV; + if (chip == NULL) { + rc = -ENODEV; + goto err_out; + } - if (test_and_set_bit(0, &chip->is_open)) { + if (chip->num_opens) { dev_dbg(chip->dev, "Another process owns this TPM\n"); - put_device(chip->dev); - return -EBUSY; + rc = -EBUSY; + goto err_out; } + 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) { - clear_bit(0, &chip->is_open); + chip->num_opens--; 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); - kfree(chip->data_buffer); - clear_bit(0, &chip->is_open); + chip->num_opens--; put_device(chip->dev); + kfree(chip->data_buffer); + spin_unlock(&driver_lock); return 0; } EXPORT_SYMBOL_GPL(tpm_release); @@ -1084,11 +1093,13 @@ void tpm_remove_hardware(struct device *dev) } spin_lock(&driver_lock); - list_del_rcu(&chip->list); + + list_del(&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); @@ -1133,33 +1144,25 @@ 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); - tpm_dev_vendor_release(chip); + if (chip->vendor.release) + chip->vendor.release(dev); 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_.c probe function only for devices @@ -1168,8 +1171,8 @@ EXPORT_SYMBOL_GPL(tpm_dev_release); * 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 @@ -1228,20 +1231,21 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, 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); diff --git a/trunk/drivers/char/tpm/tpm.h b/trunk/drivers/char/tpm/tpm.h index 8e30df4a4388..e885148b4cfb 100644 --- a/trunk/drivers/char/tpm/tpm.h +++ b/trunk/drivers/char/tpm/tpm.h @@ -90,7 +90,7 @@ struct tpm_chip { struct device *dev; /* Device stuff */ int dev_num; /* /dev/tpm# */ - unsigned long is_open; /* only one allowed */ + int num_opens; /* only one allowed */ int time_expired; /* Data passed to and from the tpm via the read/write calls */ @@ -132,7 +132,6 @@ 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 *); diff --git a/trunk/drivers/char/tpm/tpm_tis.c b/trunk/drivers/char/tpm/tpm_tis.c index 717af7ad1bdf..ed1879c0dd8d 100644 --- a/trunk/drivers/char/tpm/tpm_tis.c +++ b/trunk/drivers/char/tpm/tpm_tis.c @@ -630,23 +630,12 @@ 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 @@ -694,7 +683,6 @@ 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. @@ -706,9 +694,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); diff --git a/trunk/drivers/char/tty_audit.c b/trunk/drivers/char/tty_audit.c index 5787249934c8..3582f43345a8 100644 --- a/trunk/drivers/char/tty_audit.c +++ b/trunk/drivers/char/tty_audit.c @@ -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_hex(ab, buf->data, buf->valid); + audit_log_n_untrustedstring(ab, buf->data, buf->valid); audit_log_end(ab); } buf->valid = 0; diff --git a/trunk/drivers/char/tty_buffer.c b/trunk/drivers/char/tty_buffer.c deleted file mode 100644 index 810ee25d66a4..000000000000 --- a/trunk/drivers/char/tty_buffer.c +++ /dev/null @@ -1,511 +0,0 @@ -/* - * Tty buffer allocation management - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/** - * 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); -} - diff --git a/trunk/drivers/char/tty_io.c b/trunk/drivers/char/tty_io.c index 7053d6333692..e4dce8709541 100644 --- a/trunk/drivers/char/tty_io.c +++ b/trunk/drivers/char/tty_io.c @@ -49,7 +49,7 @@ * implement CONFIG_VT and generalize console device interface. * -- Marko Kohtala , March 97 * - * Rewrote tty_init_dev and tty_release_dev to eliminate races. + * Rewrote init_dev and release_dev to eliminate races. * -- Bill Hawes , June 97 * * Added devfs support. @@ -136,6 +136,13 @@ 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 *, @@ -164,11 +171,13 @@ static void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty); * Locking: none */ -struct tty_struct *alloc_tty_struct(void) +static 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 @@ -178,7 +187,7 @@ struct tty_struct *alloc_tty_struct(void) * Locking: none. Must be called after tty is definitely unused */ -void free_tty_struct(struct tty_struct *tty) +static inline void free_tty_struct(struct tty_struct *tty) { kfree(tty->write_buf); tty_buffer_free_all(tty); @@ -254,6 +263,398 @@ 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 @@ -274,7 +675,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 tty_driver_kref_get(p); + return p; } return NULL; } @@ -318,7 +719,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 = tty_driver_kref_get(p); + res = p; *line = tty_line; break; } @@ -418,6 +819,20 @@ 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, @@ -538,7 +953,6 @@ 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; @@ -605,12 +1019,8 @@ 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; @@ -636,10 +1046,6 @@ 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 @@ -708,23 +1114,6 @@ 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 @@ -778,14 +1167,16 @@ 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(¤t->sighand->siglock); @@ -797,6 +1188,7 @@ 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) { @@ -811,6 +1203,8 @@ void disassociate_ctty(int on_exit) current->signal->tty_old_pgrp = NULL; spin_unlock_irq(¤t->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; @@ -820,13 +1214,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); @@ -1026,19 +1420,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_chunk; + unsigned char *buf; if (chunk < 1024) chunk = 1024; - buf_chunk = kmalloc(chunk, GFP_KERNEL); - if (!buf_chunk) { + buf = kmalloc(chunk, GFP_KERNEL); + if (!buf) { ret = -ENOMEM; goto out; } kfree(tty->write_buf); tty->write_cnt = chunk; - tty->write_buf = buf_chunk; + tty->write_buf = buf; } /* Do the write .. */ @@ -1072,31 +1466,6 @@ static inline ssize_t do_tty_write( 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 @@ -1164,6 +1533,42 @@ 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"; /** @@ -1187,7 +1592,7 @@ static void pty_line_name(struct tty_driver *driver, int index, char *p) } /** - * tty_line_name - generate name for a tty + * pty_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 @@ -1199,152 +1604,14 @@ static void pty_line_name(struct tty_driver *driver, int index, char *p) */ static void tty_line_name(struct tty_driver *driver, int index, char *p) { - sprintf(p, "%s%d", driver->name, index + driver->name_base); -} - -/** - * 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; + sprintf(p, "%s%d", driver->name, index + driver->name_base); } /** - * tty_init_dev - initialise a tty device + * init_dev - initialise a tty device * @driver: tty driver we are opening a device on * @idx: device index - * @ret_tty: returned tty structure - * @first_ok: ok to open a new device (used by ptmx) + * @tty: returned tty structure * * Prepare a tty device. This may not be a "new" clean device but * could also be an active device. The pty drivers require special @@ -1364,16 +1631,37 @@ static int tty_reopen(struct tty_struct *tty) * relaxed for the (most common) case of reopening a tty. */ -struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx, - int first_ok) +static int init_dev(struct tty_driver *driver, int idx, + struct tty_struct **ret_tty) { - struct tty_struct *tty; - int retval; + 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; - /* 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); + /* 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; /* * First time open is complex, especially for PTY devices. @@ -1383,69 +1671,189 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx, * and locked termios may be retained.) */ - if (!try_module_get(driver->owner)) - return ERR_PTR(-ENODEV); + if (!try_module_get(driver->owner)) { + retval = -ENODEV; + goto end_init; + } + + o_tty = NULL; + tp = o_tp = NULL; + ltp = o_ltp = NULL; tty = alloc_tty_struct(); if (!tty) goto fail_no_mem; - initialize_tty_struct(tty, driver, idx); + 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; + } - retval = tty_driver_install_tty(driver, tty); - if (retval < 0) { - free_tty_struct(tty); - module_put(driver->owner); - return ERR_PTR(retval); + /* + * 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; } + /* + * 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, tty->link); + retval = tty_ldisc_setup(tty, o_tty); + if (retval) goto release_mem_out; - return tty; + 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); fail_no_mem: module_put(driver->owner); - return ERR_PTR(-ENOMEM); + retval = -ENOMEM; + goto end_init; /* call the tty release_tty routine to clean out this slot */ release_mem_out: if (printk_ratelimit()) - printk(KERN_INFO "tty_init_dev: ldisc open failed, " + printk(KERN_INFO "init_dev: ldisc open failed, " "clearing slot %d\n", idx); release_tty(tty, idx); - 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); + goto end_init; } -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 @@ -1455,19 +1863,31 @@ EXPORT_SYMBOL(tty_shutdown); * 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 kref *kref) +static void release_one_tty(struct tty_struct *tty, int idx) { - struct tty_struct *tty = container_of(kref, struct tty_struct, kref); - struct tty_driver *driver = tty->driver; + 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); + } + - if (tty->ops->shutdown) - tty->ops->shutdown(tty); - else - tty_shutdown(tty); tty->magic = 0; - tty_driver_kref_put(driver); - module_put(driver->owner); + tty->driver->refcount--; file_list_lock(); list_del_init(&tty->tty_files); @@ -1476,21 +1896,6 @@ static void release_one_tty(struct kref *kref) 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 * @@ -1502,16 +1907,15 @@ EXPORT_SYMBOL(tty_kref_put); * 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) { - /* This should always be true but check for the moment */ - WARN_ON(tty->index != idx); + struct tty_driver *driver = tty->driver; if (tty->link) - tty_kref_put(tty->link); - tty_kref_put(tty); + release_one_tty(tty->link, idx); + release_one_tty(tty, idx); + module_put(driver->owner); } /* @@ -1522,21 +1926,20 @@ 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. */ -void tty_release_dev(struct file *filp) +static void 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, inode, "tty_release_dev")) + if (tty_paranoia_check(tty, filp->f_path.dentry->d_inode, + "release_dev")) return; - check_tty_count(tty, "tty_release_dev"); + check_tty_count(tty, "release_dev"); tty_fasync(-1, filp, 0); @@ -1548,27 +1951,33 @@ void tty_release_dev(struct file *filp) #ifdef TTY_PARANOIA_CHECK if (idx < 0 || idx >= tty->driver->num) { - printk(KERN_DEBUG "tty_release_dev: bad idx when trying to " + printk(KERN_DEBUG "release_dev: bad idx when trying to " "free (%s)\n", tty->name); return; } - if (!devpts) { + if (!(tty->driver->flags & TTY_DRIVER_DEVPTS_MEM)) { if (tty != tty->driver->ttys[idx]) { - printk(KERN_DEBUG "tty_release_dev: driver.table[%d] not tty " + printk(KERN_DEBUG "release_dev: driver.table[%d] not tty " "for (%s)\n", idx, tty->name); return; } if (tty->termios != tty->driver->termios[idx]) { - printk(KERN_DEBUG "tty_release_dev: driver.termios[%d] not termios " + printk(KERN_DEBUG "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 "tty_release_dev of %s (tty count=%d)...", + printk(KERN_DEBUG "release_dev of %s (tty count=%d)...", tty_name(tty, buf), tty->count); #endif @@ -1576,19 +1985,26 @@ void tty_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 "tty_release_dev: other->table[%d] " + printk(KERN_DEBUG "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 "tty_release_dev: other->termios[%d] " + printk(KERN_DEBUG "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 "tty_release_dev: bad pty pointers\n"); + printk(KERN_DEBUG "release_dev: bad pty pointers\n"); return; } } @@ -1646,7 +2062,7 @@ void tty_release_dev(struct file *filp) if (!do_sleep) break; - printk(KERN_WARNING "tty_release_dev: %s: read/write wait queue " + printk(KERN_WARNING "release_dev: %s: read/write wait queue " "active!\n", tty_name(tty, buf)); mutex_unlock(&tty_mutex); schedule(); @@ -1659,14 +2075,14 @@ void tty_release_dev(struct file *filp) */ if (pty_master) { if (--o_tty->count < 0) { - printk(KERN_WARNING "tty_release_dev: bad pty slave count " + printk(KERN_WARNING "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 "tty_release_dev: bad tty->count (%d) for %s\n", + printk(KERN_WARNING "release_dev: bad tty->count (%d) for %s\n", tty->count, tty_name(tty, buf)); tty->count = 0; } @@ -1729,11 +2145,11 @@ void tty_release_dev(struct file *filp) /* Make this pty number available for reallocation */ if (devpts) - devpts_kill_index(inode, idx); + devpts_kill_index(idx); } /** - * __tty_open - open a tty device + * tty_open - open a tty device * @inode: inode of device file * @filp: file pointer to tty * @@ -1748,14 +2164,14 @@ void tty_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 tty_init_dev work. + * Locking: tty_mutex protects tty, get_tty_driver and 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 = NULL; + struct tty_struct *tty; int noctty, retval; struct tty_driver *driver; int index; @@ -1777,25 +2193,23 @@ static int __tty_open(struct inode *inode, struct file *filp) mutex_unlock(&tty_mutex); return -ENXIO; } - driver = tty_driver_kref_get(tty->driver); + driver = 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 = tty_driver_kref_get(console_driver); + driver = console_driver; index = fg_console; noctty = 1; goto got_driver; } #endif if (device == MKDEV(TTYAUX_MAJOR, 1)) { - driver = tty_driver_kref_get(console_device(&index)); + driver = console_device(&index); if (driver) { /* Don't let /dev/console block */ filp->f_flags |= O_NONBLOCK; @@ -1812,25 +2226,10 @@ static int __tty_open(struct inode *inode, struct file *filp) return -ENODEV; } got_driver: - 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); - + retval = init_dev(driver, index, &tty); mutex_unlock(&tty_mutex); - tty_driver_kref_put(driver); - if (IS_ERR(tty)) - return PTR_ERR(tty); + if (retval) + return retval; filp->private_data = tty; file_move(filp, &tty->tty_files); @@ -1858,7 +2257,7 @@ static int __tty_open(struct inode *inode, struct file *filp) printk(KERN_DEBUG "error %d in opening %s...", retval, tty->name); #endif - tty_release_dev(filp); + release_dev(filp); if (retval != -ERESTARTSYS) return retval; if (signal_pending(current)) @@ -1897,6 +2296,69 @@ 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 @@ -1907,13 +2369,13 @@ static int tty_open(struct inode *inode, struct file *filp) * this tty. There may however be several such references. * * Locking: - * Takes bkl. See tty_release_dev + * Takes bkl. See release_dev */ static int tty_release(struct inode *inode, struct file *filp) { lock_kernel(); - tty_release_dev(filp); + release_dev(filp); unlock_kernel(); return 0; } @@ -2062,7 +2524,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, &real_tty->winsize, sizeof(*ws))) + if (!memcmp(ws, &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 */ @@ -2534,7 +2996,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case TIOCSTI: return tiocsti(tty, p); case TIOCGWINSZ: - return tiocgwinsz(real_tty, p); + return tiocgwinsz(tty, p); case TIOCSWINSZ: return tiocswinsz(tty, real_tty, p); case TIOCCONS: @@ -2564,6 +3026,10 @@ 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 */ @@ -2753,6 +3219,113 @@ 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 @@ -2763,11 +3336,9 @@ EXPORT_SYMBOL(do_SAK); * Locking: none - tty in question must not be exposed at this point */ -void initialize_tty_struct(struct tty_struct *tty, - struct tty_driver *driver, int idx) +static void initialize_tty_struct(struct tty_struct *tty) { memset(tty, 0, sizeof(struct tty_struct)); - kref_init(&tty->kref); tty->magic = TTY_MAGIC; tty_ldisc_init(tty); tty->session = NULL; @@ -2775,6 +3346,7 @@ 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); @@ -2785,11 +3357,6 @@ 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); } /** @@ -2810,9 +3377,10 @@ 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); -struct class *tty_class; +static struct class *tty_class; /** * tty_register_device - register a tty device @@ -2852,7 +3420,6 @@ 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 @@ -2870,6 +3437,8 @@ 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) @@ -2878,65 +3447,27 @@ 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); -static void destruct_tty_driver(struct kref *kref) +void put_tty_driver(struct tty_driver *driver) { - 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); -void put_tty_driver(struct tty_driver *d) -{ - tty_driver_kref_put(d); -} +EXPORT_SYMBOL(alloc_tty_driver); EXPORT_SYMBOL(put_tty_driver); +EXPORT_SYMBOL(tty_set_operations); /* * Called by a tty driver to register itself. @@ -2948,8 +3479,11 @@ 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 * 2 * sizeof(void *), GFP_KERNEL); + p = kzalloc(driver->num * 3 * sizeof(void *), GFP_KERNEL); if (!p) return -ENOMEM; } @@ -2973,9 +3507,12 @@ 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); @@ -2984,7 +3521,7 @@ int tty_register_driver(struct tty_driver *driver) if (error) { unregister_chrdev_region(dev, driver->num); driver->ttys = NULL; - driver->termios = NULL; + driver->termios = driver->termios_locked = NULL; kfree(p); return error; } @@ -2998,7 +3535,6 @@ 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; } @@ -3009,19 +3545,46 @@ EXPORT_SYMBOL(tty_register_driver); */ int tty_unregister_driver(struct tty_driver *driver) { -#if 0 - /* FIXME */ + int i; + struct ktermios *tp; + void *p; + 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) @@ -3032,12 +3595,9 @@ 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 */ @@ -3053,13 +3613,9 @@ 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_kref_get(tty); + tsk->signal->tty = tty; tsk->signal->tty_old_pgrp = NULL; } @@ -3073,20 +3629,18 @@ static void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty) struct tty_struct *get_current_tty(void) { struct tty_struct *tty; - unsigned long flags; - - spin_lock_irqsave(¤t->sighand->siglock, flags); - tty = tty_kref_get(current->signal->tty); - spin_unlock_irqrestore(¤t->sighand->siglock, flags); + 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(); 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. @@ -3124,6 +3678,12 @@ 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 @@ -3135,18 +3695,32 @@ 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(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), NULL, + device_create_drvdata(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(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1), NULL, + device_create_drvdata(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 - vty_init(&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_drvdata(tty_class, NULL, MKDEV(TTY_MAJOR, 0), NULL, "tty0"); + + vty_init(); #endif return 0; } diff --git a/trunk/drivers/char/tty_ioctl.c b/trunk/drivers/char/tty_ioctl.c index a408c8e487ec..bf34e4597421 100644 --- a/trunk/drivers/char/tty_ioctl.c +++ b/trunk/drivers/char/tty_ioctl.c @@ -40,15 +40,6 @@ #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) @@ -56,48 +47,25 @@ 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. - */ +EXPORT_SYMBOL(tty_driver_flush_buffer); void tty_throttle(struct tty_struct *tty) { @@ -108,13 +76,6 @@ 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) && @@ -151,11 +112,6 @@ 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) @@ -390,16 +346,6 @@ 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); @@ -484,11 +430,12 @@ 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_mutex + * Locking: termios_sem */ 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; @@ -504,6 +451,18 @@ 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) { @@ -549,7 +508,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_mutex locks + * Called functions take ldisc and termios_sem locks */ static int set_termios(struct tty_struct *tty, void __user *arg, int opt) @@ -620,51 +579,25 @@ static int get_termio(struct tty_struct *tty, struct termio __user *termio) return 0; } - -#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) +static unsigned long inq_canon(struct tty_struct *tty) { - struct termiox tnew; - struct tty_ldisc *ld; + int nr, head, tail; - 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); - } - if (opt & TERMIOS_WAIT) { - tty_wait_until_sent(tty, 0); - if (signal_pending(current)) - return -EINTR; + 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); } - - mutex_lock(&tty->termios_mutex); - if (tty->ops->set_termiox) - tty->ops->set_termiox(tty, &tnew); - mutex_unlock(&tty->termios_mutex); - return 0; + return nr; } -#endif - - #ifdef TIOCGETP /* * These are deprecated, but there is limited support.. @@ -738,7 +671,7 @@ static void set_sgflags(struct ktermios *termios, int flags) * Updates a terminal from the legacy BSD style terminal information * structure. * - * Locking: termios_mutex + * Locking: termios_sem */ static int set_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb) @@ -916,7 +849,6 @@ 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) @@ -952,24 +884,18 @@ 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)) - ret = -EFAULT; - mutex_unlock(&real_tty->termios_mutex); - return ret; + return -EFAULT; + return 0; #else case TCGETS: - mutex_lock(&real_tty->termios_mutex); if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios)) - ret = -EFAULT; - mutex_unlock(&real_tty->termios_mutex); - return ret; + return -EFAULT; + return 0; case TCGETS2: - mutex_lock(&real_tty->termios_mutex); if (kernel_termios_to_user_termios((struct termios2 __user *)arg, real_tty->termios)) - ret = -EFAULT; - mutex_unlock(&real_tty->termios_mutex); - return ret; + return -EFAULT; + return 0; case TCSETSF2: return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT); case TCSETSW2: @@ -987,59 +913,34 @@ 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)) - ret = -EFAULT; - mutex_unlock(&real_tty->termios_mutex); - return ret; + return -EFAULT; + return 0; 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)) - ret = -EFAULT; - mutex_unlock(&real_tty->termios_mutex); - return ret; + return -EFAULT; + return 0; #else case TIOCGLCKTRMIOS: - mutex_lock(&real_tty->termios_mutex); if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios_locked)) - ret = -EFAULT; - mutex_unlock(&real_tty->termios_mutex); - return ret; + return -EFAULT; + return 0; case TIOCSLCKTRMIOS: if (!capable(CAP_SYS_ADMIN)) - ret = -EPERM; - mutex_lock(&real_tty->termios_mutex); + return -EPERM; if (user_termios_to_kernel_termios_1(real_tty->termios_locked, (struct termios __user *) arg)) - ret = -EFAULT; - mutex_unlock(&real_tty->termios_mutex); - return ret; + return -EFAULT; + return 0; #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: - mutex_lock(&real_tty->termios_mutex); - ret = put_user(C_CLOCAL(real_tty) ? 1 : 0, + /* FIXME: for correctness we may need to take the termios + lock here - review */ + return 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; @@ -1079,7 +980,7 @@ int tty_perform_flush(struct tty_struct *tty, unsigned long arg) } EXPORT_SYMBOL_GPL(tty_perform_flush); -int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file, +int n_tty_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) { unsigned long flags; @@ -1117,6 +1018,13 @@ int n_tty_ioctl_helper(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; @@ -1142,4 +1050,4 @@ int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file, return tty_mode_ioctl(tty, file, cmd, arg); } } -EXPORT_SYMBOL(n_tty_ioctl_helper); +EXPORT_SYMBOL(n_tty_ioctl); diff --git a/trunk/drivers/char/tty_port.c b/trunk/drivers/char/tty_port.c deleted file mode 100644 index 553b0e9d8d17..000000000000 --- a/trunk/drivers/char/tty_port.c +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Tty port functions - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -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); diff --git a/trunk/drivers/char/vt.c b/trunk/drivers/char/vt.c index 57029fefd64a..60359c360912 100644 --- a/trunk/drivers/char/vt.c +++ b/trunk/drivers/char/vt.c @@ -100,10 +100,10 @@ #include #include #include -#include -#include + +#include #include -#include +#include #define MAX_NR_CON_DRIVER 16 @@ -2136,9 +2136,27 @@ 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; @@ -2352,6 +2370,8 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co FLUSH console_conditional_schedule(); release_console_sem(); + +out: notify_update(vc); return n; #undef FLUSH @@ -2563,6 +2583,8 @@ 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)) @@ -2756,12 +2778,6 @@ 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; @@ -2782,20 +2798,34 @@ 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) { - /* Nothing to do - we defer to shutdown */ -} - -static void con_shutdown(struct tty_struct *tty) -{ - struct vc_data *vc = tty->driver_data; - BUG_ON(vc == NULL); + mutex_lock(&tty_mutex); acquire_console_sem(); - vc->vc_tty = NULL; - vcs_remove_sysfs(tty); + if (tty && tty->count == 1) { + struct vc_data *vc = tty->driver_data; + + 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; + } release_console_sem(); - tty_shutdown(tty); + mutex_unlock(&tty_mutex); } static int default_italic_color = 2; // green (ASCII) @@ -2920,19 +2950,10 @@ static const struct tty_operations con_ops = { .throttle = con_throttle, .unthrottle = con_unthrottle, .resize = vt_resize, - .shutdown = con_shutdown }; -static struct cdev vc0_cdev; - -int __init vty_init(const struct file_operations *console_fops) +int __init vty_init(void) { - 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); @@ -2951,6 +2972,7 @@ int __init vty_init(const struct file_operations *console_fops) 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 @@ -3444,7 +3466,7 @@ int register_con_driver(const struct consw *csw, int first, int last) if (retval) goto err; - con_driver->dev = device_create(vtconsole_class, NULL, + con_driver->dev = device_create_drvdata(vtconsole_class, NULL, MKDEV(0, con_driver->node), NULL, "vtcon%i", con_driver->node); @@ -3555,7 +3577,7 @@ static int __init vtconsole_class_init(void) struct con_driver *con = ®istered_con_driver[i]; if (con->con && !con->dev) { - con->dev = device_create(vtconsole_class, NULL, + con->dev = device_create_drvdata(vtconsole_class, NULL, MKDEV(0, con->node), NULL, "vtcon%i", con->node); diff --git a/trunk/drivers/char/vt_ioctl.c b/trunk/drivers/char/vt_ioctl.c index 8944ce508e2f..c904e9ad4a71 100644 --- a/trunk/drivers/char/vt_ioctl.c +++ b/trunk/drivers/char/vt_ioctl.c @@ -395,8 +395,6 @@ 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; diff --git a/trunk/drivers/isdn/capi/capi.c b/trunk/drivers/isdn/capi/capi.c index 798d7f3e42ef..871b0cbca5e4 100644 --- a/trunk/drivers/isdn/capi/capi.c +++ b/trunk/drivers/isdn/capi/capi.c @@ -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_helper(tty, file, cmd, arg); + error = n_tty_ioctl (tty, file, cmd, arg); break; } return error; diff --git a/trunk/drivers/isdn/gigaset/ser-gigaset.c b/trunk/drivers/isdn/gigaset/ser-gigaset.c index 07052ed2a0c5..5e89fa177816 100644 --- a/trunk/drivers/isdn/gigaset/ser-gigaset.c +++ b/trunk/drivers/isdn/gigaset/ser-gigaset.c @@ -571,7 +571,6 @@ 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) @@ -643,11 +642,10 @@ gigaset_tty_ioctl(struct tty_struct *tty, struct file *file, return -ENXIO; switch (cmd) { - - case FIONREAD: - /* unused, always return zero */ - val = 0; - rc = put_user(val, p); + case TCGETS: + case TCGETA: + /* pass through to underlying serial device */ + rc = n_tty_ioctl(tty, file, cmd, arg); break; case TCFLSH: @@ -661,13 +659,20 @@ gigaset_tty_ioctl(struct tty_struct *tty, struct file *file, flush_send_queue(cs); break; } - /* Pass through */ + /* flush the serial port's buffer */ + rc = n_tty_ioctl(tty, file, cmd, arg); + break; - default: - /* pass through to underlying serial device */ - rc = n_tty_ioctl_helper(tty, file, cmd, arg); + case FIONREAD: + /* unused, always return zero */ + val = 0; + rc = put_user(val, p); break; + + default: + rc = -ENOIOCTLCMD; } + cs_put(cs); return rc; } @@ -675,8 +680,6 @@ 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) diff --git a/trunk/drivers/media/video/cafe_ccic.c b/trunk/drivers/media/video/cafe_ccic.c index 08efbe7254ff..5405c30dbb04 100644 --- a/trunk/drivers/media/video/cafe_ccic.c +++ b/trunk/drivers/media/video/cafe_ccic.c @@ -2092,8 +2092,15 @@ 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. */ @@ -2281,8 +2288,8 @@ static int cafe_pci_resume(struct pci_dev *pdev) static struct pci_device_id cafe_ids[] = { - { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, - PCI_DEVICE_ID_MARVELL_88ALP01_CCIC) }, + { PCI_DEVICE(0x11ab, 0x4100) }, /* Eventual real ID */ + { PCI_DEVICE(0x11ab, 0x4102) }, /* Really eventual real ID */ { 0, } }; diff --git a/trunk/drivers/mmc/host/sdhci-pci.c b/trunk/drivers/mmc/host/sdhci-pci.c index 9bd7026b0021..0a84f10d719c 100644 --- a/trunk/drivers/mmc/host/sdhci-pci.c +++ b/trunk/drivers/mmc/host/sdhci-pci.c @@ -327,7 +327,7 @@ static const struct pci_device_id pci_ids[] __devinitdata = { { .vendor = PCI_VENDOR_ID_MARVELL, - .device = PCI_DEVICE_ID_MARVELL_88ALP01_SD, + .device = PCI_DEVICE_ID_MARVELL_CAFE_SD, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .driver_data = (kernel_ulong_t)&sdhci_cafe, diff --git a/trunk/drivers/mtd/nand/cafe_nand.c b/trunk/drivers/mtd/nand/cafe_nand.c index b8064bf3aee4..95345d051579 100644 --- a/trunk/drivers/mtd/nand/cafe_nand.c +++ b/trunk/drivers/mtd/nand/cafe_nand.c @@ -1,9 +1,6 @@ /* * 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 */ @@ -845,8 +842,7 @@ static void __devexit cafe_nand_remove(struct pci_dev *pdev) } static struct pci_device_id cafe_nand_tbl[] = { - { PCI_VENDOR_ID_MARVELL, PCI_DEVICE_ID_MARVELL_88ALP01_NAND, - PCI_ANY_ID, PCI_ANY_ID }, + { 0x11ab, 0x4100, PCI_ANY_ID, PCI_ANY_ID }, { } }; diff --git a/trunk/drivers/net/wan/Kconfig b/trunk/drivers/net/wan/Kconfig index 21efd99b9294..2ae2ec40015d 100644 --- a/trunk/drivers/net/wan/Kconfig +++ b/trunk/drivers/net/wan/Kconfig @@ -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 && BROKEN + depends on HDLC && PCI ---help--- Driver for the Cyclades-PC300 synchronous communication boards. diff --git a/trunk/drivers/oprofile/buffer_sync.c b/trunk/drivers/oprofile/buffer_sync.c index ed982273fb8b..9304c4555079 100644 --- a/trunk/drivers/oprofile/buffer_sync.c +++ b/trunk/drivers/oprofile/buffer_sync.c @@ -5,7 +5,6 @@ * @remark Read the file COPYING * * @author John Levon - * @author Barry Kasindorf * * This is the core of the buffer management. Each * CPU buffer is processed and entered into the @@ -34,7 +33,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; @@ -49,11 +48,10 @@ 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); @@ -64,14 +62,13 @@ task_free_notify(struct notifier_block *self, unsigned long val, void *data) /* 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; } @@ -80,12 +77,11 @@ task_exit_notify(struct notifier_block *self, unsigned long val, void *data) * 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); @@ -103,12 +99,11 @@ munmap_notify(struct notifier_block *self, unsigned long val, void *data) 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) @@ -123,7 +118,7 @@ module_load_notify(struct notifier_block *self, unsigned long val, void *data) return 0; } - + static struct notifier_block task_free_nb = { .notifier_call = task_free_notify, }; @@ -140,7 +135,7 @@ static struct notifier_block module_load_nb = { .notifier_call = module_load_notify, }; - + static void end_sync(void) { end_cpu_work(); @@ -213,14 +208,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; @@ -240,14 +235,13 @@ static unsigned long get_exec_dcookie(struct mm_struct *mm) * 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; @@ -269,20 +263,9 @@ lookup_dcookie(struct mm_struct *mm, unsigned long addr, off_t *offset) 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); @@ -295,16 +278,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 */ @@ -313,7 +296,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); @@ -321,78 +304,13 @@ 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) { @@ -401,13 +319,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; @@ -423,13 +341,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); @@ -441,9 +359,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; @@ -452,9 +370,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; @@ -465,10 +383,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; @@ -494,6 +412,19 @@ 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, @@ -504,8 +435,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); @@ -562,7 +493,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; @@ -570,7 +501,7 @@ void sync_buffer(int cpu) unsigned long available; mutex_lock(&buffer_mutex); - + add_cpu_switch(cpu); /* Remember, only we can modify tail_pos */ @@ -578,8 +509,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 */ @@ -590,18 +521,8 @@ 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; @@ -612,11 +533,13 @@ 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); + } } } diff --git a/trunk/drivers/oprofile/cpu_buffer.c b/trunk/drivers/oprofile/cpu_buffer.c index e1bd5a937f6c..7ba78e6d210e 100644 --- a/trunk/drivers/oprofile/cpu_buffer.c +++ b/trunk/drivers/oprofile/cpu_buffer.c @@ -5,7 +5,6 @@ * @remark Read the file COPYING * * @author John Levon - * @author Barry Kasindorf * * Each CPU has a local buffer that stores PC value/event * pairs. We also log context switches when we notice them. @@ -210,7 +209,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++; @@ -255,75 +254,6 @@ 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); @@ -366,7 +296,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(KERN_DEBUG "WQ on CPU%d, prefer CPU%d\n", + printk("WQ on CPU%d, prefer CPU%d\n", smp_processor_id(), b->cpu); } sync_buffer(b->cpu); diff --git a/trunk/drivers/oprofile/cpu_buffer.h b/trunk/drivers/oprofile/cpu_buffer.h index 9c44d004da69..c3e366b52261 100644 --- a/trunk/drivers/oprofile/cpu_buffer.h +++ b/trunk/drivers/oprofile/cpu_buffer.h @@ -55,7 +55,5 @@ 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 */ diff --git a/trunk/drivers/s390/char/fs3270.c b/trunk/drivers/s390/char/fs3270.c index 40759c33477d..d18e6d2e0b49 100644 --- a/trunk/drivers/s390/char/fs3270.c +++ b/trunk/drivers/s390/char/fs3270.c @@ -418,22 +418,25 @@ fs3270_open(struct inode *inode, struct file *filp) { struct fs3270 *fp; struct idal_buffer *ib; - int minor, rc = 0; + int minor, rc; 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 = get_current_tty(); + struct tty_struct *tty; + mutex_lock(&tty_mutex); + tty = get_current_tty(); if (!tty || tty->driver->major != IBM_TTY3270_MAJOR) { - tty_kref_put(tty); - return -ENODEV; + mutex_unlock(&tty_mutex); + rc = -ENODEV; + goto out; } minor = tty->index + RAW3270_FIRSTMINOR; - tty_kref_put(tty); + mutex_unlock(&tty_mutex); } - 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)) { @@ -475,7 +478,7 @@ fs3270_open(struct inode *inode, struct file *filp) filp->private_data = fp; out: unlock_kernel(); - return rc; + return 0; } /* diff --git a/trunk/drivers/serial/8250.c b/trunk/drivers/serial/8250.c index d4104a3bbe87..9ccc563d8730 100644 --- a/trunk/drivers/serial/8250.c +++ b/trunk/drivers/serial/8250.c @@ -44,10 +44,6 @@ #include "8250.h" -#ifdef CONFIG_SPARC -#include "suncore.h" -#endif - /* * Configuration: * share_irqs - whether we pass IRQF_SHARED to request_irq(). This option @@ -57,13 +53,6 @@ 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. */ @@ -547,7 +536,7 @@ static unsigned int serial_icr_read(struct uart_8250_port *up, int offset) /* * FIFO support. */ -static void serial8250_clear_fifos(struct uart_8250_port *p) +static inline void serial8250_clear_fifos(struct uart_8250_port *p) { if (p->capabilities & UART_CAP_FIFO) { serial_outp(p, UART_FCR, UART_FCR_ENABLE_FIFO); @@ -562,7 +551,7 @@ static 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 void serial8250_set_sleep(struct uart_8250_port *p, int sleep) +static inline void serial8250_set_sleep(struct uart_8250_port *p, int sleep) { if (p->capabilities & UART_CAP_SLEEP) { if (p->capabilities & UART_CAP_EFR) { @@ -1004,7 +993,7 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags) return; DEBUG_AUTOCONF("ttyS%d: autoconf (0x%04x, 0x%p): ", - serial_index(&up->port), up->port.iobase, up->port.membase); + up->port.line, up->port.iobase, up->port.membase); /* * We really do need global IRQs disabled here - we're going to @@ -1139,8 +1128,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", - serial_index(&up->port), up->capabilities, - uart_config[up->port.type].flags); + up->port.line, up->capabilities, + uart_config[up->port.type].flags); } up->port.fifosize = uart_config[up->port.type].fifo_size; @@ -1435,7 +1424,8 @@ static unsigned int check_modem_status(struct uart_8250_port *up) /* * This handles the interrupt from one port. */ -static void serial8250_handle_port(struct uart_8250_port *up) +static inline void +serial8250_handle_port(struct uart_8250_port *up) { unsigned int status; unsigned long flags; @@ -1729,7 +1719,7 @@ static void serial8250_break_ctl(struct uart_port *port, int break_state) /* * Wait for transmitter & holding register to empty */ -static void wait_for_xmitr(struct uart_8250_port *up, int bits) +static inline void wait_for_xmitr(struct uart_8250_port *up, int bits) { unsigned int status, tmout = 10000; @@ -1864,8 +1854,7 @@ static int serial8250_startup(struct uart_port *port) */ if (!(up->port.flags & UPF_BUGGY_UART) && (serial_inp(up, UART_LSR) == 0xff)) { - printk(KERN_INFO "ttyS%d: LSR safety check engaged!\n", - serial_index(&up->port)); + printk("ttyS%d: LSR safety check engaged!\n", up->port.line); return -ENODEV; } @@ -1920,8 +1909,7 @@ 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", - serial_index(port)); + pr_debug("ttyS%d - using backup timer\n", port->line); } } @@ -1981,7 +1969,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", - serial_index(port)); + port->line); } } else { up->bugs &= ~UART_BUG_TXEN; @@ -2642,6 +2630,7 @@ 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, @@ -2688,6 +2677,7 @@ static struct uart_driver serial8250_reg = { .dev_name = "ttyS", .major = TTY_MAJOR, .minor = 64, + .nr = UART_NR, .cons = SERIAL8250_CONSOLE, }; @@ -2969,12 +2959,10 @@ static int __init serial8250_init(void) "%d ports, IRQ sharing %sabled\n", nr_uarts, share_irqs ? "en" : "dis"); -#ifdef CONFIG_SPARC - ret = sunserial_register_minors(&serial8250_reg, UART_NR); -#else - serial8250_reg.nr = UART_NR; + for (i = 0; i < NR_IRQS; i++) + spin_lock_init(&irq_lists[i].lock); + ret = uart_register_driver(&serial8250_reg); -#endif if (ret) goto out; @@ -2999,11 +2987,7 @@ 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; } @@ -3022,11 +3006,7 @@ 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); diff --git a/trunk/drivers/serial/8250_pci.c b/trunk/drivers/serial/8250_pci.c index c014ffb110e9..c2f23933155b 100644 --- a/trunk/drivers/serial/8250_pci.c +++ b/trunk/drivers/serial/8250_pci.c @@ -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) - printk(KERN_ERR "pciserial: Unable to re-enable ports, trying to continue.\n"); + return err; + pciserial_resume_ports(priv); } return 0; diff --git a/trunk/drivers/serial/Kconfig b/trunk/drivers/serial/Kconfig index 31786b3b0a68..77cb34270fc1 100644 --- a/trunk/drivers/serial/Kconfig +++ b/trunk/drivers/serial/Kconfig @@ -9,6 +9,7 @@ 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 @@ -993,12 +994,24 @@ 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" + bool "Coldfire serial support (new style driver)" depends on COLDFIRE select SERIAL_CORE help - This serial driver supports the Freescale Coldfire serial ports. + This new serial driver supports the Freescale Coldfire serial ports + using the new serial driver subsystem. config SERIAL_MCF_BAUDRATE int "Default baudrate for Coldfire serial ports" diff --git a/trunk/drivers/serial/Makefile b/trunk/drivers/serial/Makefile index 0c17c8ddb19d..7e7383e890d8 100644 --- a/trunk/drivers/serial/Makefile +++ b/trunk/drivers/serial/Makefile @@ -4,16 +4,6 @@ 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 @@ -41,10 +31,16 @@ 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 diff --git a/trunk/drivers/serial/bfin_5xx.c b/trunk/drivers/serial/bfin_5xx.c index 569f0e2476c6..4a0d30bed9f1 100644 --- a/trunk/drivers/serial/bfin_5xx.c +++ b/trunk/drivers/serial/bfin_5xx.c @@ -1,7 +1,7 @@ /* * Blackfin On-Chip Serial Driver * - * Copyright 2006-2008 Analog Devices Inc. + * Copyright 2006-2007 Analog Devices Inc. * * Enter bugs at http://blackfin.uclinux.org/ * @@ -42,9 +42,6 @@ #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 */ @@ -129,13 +126,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(); } @@ -155,7 +152,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(); } @@ -301,11 +298,7 @@ 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)) { -#ifdef CONFIG_BF54x - /* Clear TFI bit */ - UART_PUT_LSR(uart, TFI); -#endif - UART_CLEAR_IER(uart, ETBEI); + bfin_serial_stop_tx(&uart->port); return; } @@ -324,6 +317,9 @@ 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) @@ -649,42 +645,6 @@ 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; @@ -702,20 +662,6 @@ 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 @@ -811,9 +757,6 @@ 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); } @@ -916,9 +859,8 @@ static void __init bfin_serial_init_ports(void) return; first = 0; - for (i = 0; i < nr_active_ports; i++) { + for (i = 0; i < nr_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; @@ -1019,7 +961,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_active_ports) + if (co->index == -1 || co->index >= nr_ports) co->index = 0; uart = &bfin_serial_ports[co->index]; @@ -1114,7 +1056,7 @@ static __init void early_serial_write(struct console *con, const char *s, } } -static struct __initdata console bfin_early_serial_console = { +static struct __init console bfin_early_serial_console = { .name = "early_BFuart", .write = early_serial_write, .device = uart_console_device, @@ -1130,7 +1072,7 @@ struct console __init *bfin_earlyserial_init(unsigned int port, struct bfin_serial_port *uart; struct ktermios t; - if (port == -1 || port >= nr_active_ports) + if (port == -1 || port >= nr_ports) port = 0; bfin_serial_init_ports(); bfin_early_serial_console.index = port; @@ -1158,26 +1100,20 @@ static struct uart_driver bfin_serial_reg = { static int bfin_serial_suspend(struct platform_device *dev, pm_message_t state) { - int i; + struct bfin_serial_port *uart = platform_get_drvdata(dev); - 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); - } + if (uart) + uart_suspend_port(&bfin_serial_reg, &uart->port); return 0; } static int bfin_serial_resume(struct platform_device *dev) { - int i; + struct bfin_serial_port *uart = platform_get_drvdata(dev); - 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); - } + if (uart) + uart_resume_port(&bfin_serial_reg, &uart->port); return 0; } @@ -1192,31 +1128,32 @@ static int bfin_serial_probe(struct platform_device *dev) break; if (i < dev->num_resources) { - for (i = 0; i < nr_active_ports; i++, res++) { + for (i = 0; i < nr_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 *dev) +static int bfin_serial_remove(struct platform_device *pdev) { - int i; + struct bfin_serial_port *uart = platform_get_drvdata(pdev); + - 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(bfin_serial_ports[i].cts_pin); - gpio_free(bfin_serial_ports[i].rts_pin); + gpio_free(uart->cts_pin); + gpio_free(uart->rts_pin); #endif - } + + platform_set_drvdata(pdev, NULL); + + if (uart) + uart_remove_one_port(&bfin_serial_reg, &uart->port); return 0; } diff --git a/trunk/drivers/serial/crisv10.c b/trunk/drivers/serial/crisv10.c index 211c21797ce0..bf94a770bb44 100644 --- a/trunk/drivers/serial/crisv10.c +++ b/trunk/drivers/serial/crisv10.c @@ -457,6 +457,7 @@ 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 @@ -4418,7 +4419,6 @@ 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,7 +4427,6 @@ 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 @@ -4447,6 +4446,8 @@ 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/trunk/drivers/serial/mcfserial.c b/trunk/drivers/serial/mcfserial.c new file mode 100644 index 000000000000..fbe3835f6b77 --- /dev/null +++ b/trunk/drivers/serial/mcfserial.c @@ -0,0 +1,1965 @@ +#warning This driver is deprecated. Check Kconfig for details. +/* + * mcfserial.c -- serial driver for ColdFire internal UARTS. + * + * Copyright (C) 1999-2003 Greg Ungerer + * Copyright (c) 2000-2001 Lineo, Inc. + * Copyright (C) 2001-2002 SnapGear Inc. + * + * 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. + * + * Changes: + * 08/07/2003 Daniele Bellucci + * some cleanups in mcfrs_write. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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/trunk/drivers/serial/mcfserial.h b/trunk/drivers/serial/mcfserial.h new file mode 100644 index 000000000000..56420e2cb110 --- /dev/null +++ b/trunk/drivers/serial/mcfserial.h @@ -0,0 +1,74 @@ +/* + * mcfserial.c -- serial driver for ColdFire internal UARTS. + * + * Copyright (c) 1999 Greg Ungerer + * Copyright (c) 2000-2001 Lineo, Inc. + * Copyright (c) 2002 SnapGear Inc., + * + * 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. + */ +#ifndef _MCF_SERIAL_H +#define _MCF_SERIAL_H + +#include + +#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 */ diff --git a/trunk/drivers/serial/serial_core.c b/trunk/drivers/serial/serial_core.c index 6bdf3362e3b1..f977c98cfa95 100644 --- a/trunk/drivers/serial/serial_core.c +++ b/trunk/drivers/serial/serial_core.c @@ -2051,8 +2051,7 @@ 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, - drv->tty_driver->name_base + port->line); + drv->dev_name, port->line); ops->shutdown(port); } @@ -2155,11 +2154,12 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port) switch (port->iotype) { case UPIO_PORT: - snprintf(address, sizeof(address), "I/O 0x%lx", port->iobase); + snprintf(address, sizeof(address), + "I/O 0x%x", port->iobase); break; case UPIO_HUB6: snprintf(address, sizeof(address), - "I/O 0x%lx offset 0x%x", port->iobase, port->hub6); + "I/O 0x%x offset 0x%x", port->iobase, port->hub6); break; case UPIO_MEM: case UPIO_MEM32: @@ -2177,9 +2177,7 @@ 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, - drv->tty_driver->name_base + port->line, - address, port->irq, uart_type(port)); + drv->dev_name, port->line, address, port->irq, uart_type(port)); } static void diff --git a/trunk/drivers/usb/serial/aircable.c b/trunk/drivers/usb/serial/aircable.c index 99fb7dc59c45..79ea98c66fa8 100644 --- a/trunk/drivers/usb/serial/aircable.c +++ b/trunk/drivers/usb/serial/aircable.c @@ -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 = tty_port_tty_get(&port->port); + tty = port->port.tty; if (!tty) { schedule_work(&priv->rx_work); @@ -283,13 +283,12 @@ static void aircable_read(struct work_struct *work) count = min(64, serial_buf_data_avail(priv->rx_buf)); if (count <= 0) - goto out; /* We have finished sending everything. */ + return; /* We have finished sending everything. */ tty_prepare_flip_string(tty, &data, count); if (!data) { - dev_err(&port->dev, "%s- kzalloc(%d) failed.", - __func__, count); - goto out; + err("%s- kzalloc(%d) failed.", __func__, count); + return; } serial_buf_get(priv->rx_buf, data, count); @@ -298,8 +297,7 @@ 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 */ @@ -497,7 +495,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 = tty_port_tty_get(&port->port); + tty = port->port.tty; if (tty && urb->actual_length) { if (urb->actual_length <= 2) { /* This is an incomplete package */ @@ -529,7 +527,6 @@ 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) { diff --git a/trunk/drivers/usb/serial/belkin_sa.c b/trunk/drivers/usb/serial/belkin_sa.c index 1913bc7c5f0b..2ebe06c3405a 100644 --- a/trunk/drivers/usb/serial/belkin_sa.c +++ b/trunk/drivers/usb/serial/belkin_sa.c @@ -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 = tty_port_tty_get(&port->port); + tty = port->port.tty; /* Overrun Error */ if (priv->last_lsr & BELKIN_SA_LSR_OE) { } @@ -335,7 +335,6 @@ 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); diff --git a/trunk/drivers/usb/serial/console.c b/trunk/drivers/usb/serial/console.c index 5b20de130e08..e980766bb84b 100644 --- a/trunk/drivers/usb/serial/console.c +++ b/trunk/drivers/usb/serial/console.c @@ -117,7 +117,7 @@ static int usb_console_setup(struct console *co, char *options) } port = serial->port[0]; - tty_port_tty_set(&port->port, NULL); + port->port.tty = 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; - tty_port_tty_set(&port->port, tty); + port->port.tty = 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); - tty_port_tty_set(&port->port, NULL); + port->port.tty = NULL; kfree(termios); kfree(tty); } @@ -176,7 +176,7 @@ static int usb_console_setup(struct console *co, char *options) return retval; free_termios: kfree(termios); - tty_port_tty_set(&port->port, NULL); + port->port.tty = NULL; free_tty: kfree(tty); reset_open_count: diff --git a/trunk/drivers/usb/serial/cyberjack.c b/trunk/drivers/usb/serial/cyberjack.c index 94ef36c4764b..b4d72351cb96 100644 --- a/trunk/drivers/usb/serial/cyberjack.c +++ b/trunk/drivers/usb/serial/cyberjack.c @@ -384,7 +384,7 @@ static void cyberjack_read_bulk_callback(struct urb *urb) return; } - tty = tty_port_tty_get(&port->port); + tty = port->port.tty; if (!tty) { dbg("%s - ignoring since device not open\n", __func__); return; @@ -394,7 +394,6 @@ 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); diff --git a/trunk/drivers/usb/serial/cypress_m8.c b/trunk/drivers/usb/serial/cypress_m8.c index f3514a91f915..22837a3f2f89 100644 --- a/trunk/drivers/usb/serial/cypress_m8.c +++ b/trunk/drivers/usb/serial/cypress_m8.c @@ -1286,7 +1286,7 @@ static void cypress_read_int_callback(struct urb *urb) } spin_unlock_irqrestore(&priv->lock, flags); - tty = tty_port_tty_get(&port->port); + tty = port->port.tty; 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(tty); + tty_flip_buffer_push(port->port.tty); } spin_lock_irqsave(&priv->lock, flags); @@ -1371,7 +1371,6 @@ 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. */ diff --git a/trunk/drivers/usb/serial/digi_acceleport.c b/trunk/drivers/usb/serial/digi_acceleport.c index 5756ac6d6c92..240aad1acaab 100644 --- a/trunk/drivers/usb/serial/digi_acceleport.c +++ b/trunk/drivers/usb/serial/digi_acceleport.c @@ -604,9 +604,7 @@ static void digi_wakeup_write_lock(struct work_struct *work) static void digi_wakeup_write(struct usb_serial_port *port) { - struct tty_struct *tty = tty_port_tty_get(&port->port); - tty_wakeup(tty); - tty_kref_put(tty); + tty_wakeup(port->port.tty); } @@ -1670,7 +1668,7 @@ static int digi_read_inb_callback(struct urb *urb) { struct usb_serial_port *port = urb->context; - struct tty_struct *tty; + struct tty_struct *tty = port->port.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]; @@ -1694,7 +1692,6 @@ 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 */ @@ -1738,7 +1735,6 @@ 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__); @@ -1764,7 +1760,6 @@ 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; @@ -1792,11 +1787,10 @@ 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 = tty->termios->c_cflag & CRTSCTS; - + rts = port->port.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 */ @@ -1804,14 +1798,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) { - tty->hw_stopped = 0; + port->port.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) - tty->hw_stopped = 1; + port->port.tty->hw_stopped = 1; } if (val & DIGI_READ_INPUT_SIGNALS_DSR) priv->dp_modem_signals |= TIOCM_DSR; @@ -1836,7 +1830,6 @@ 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; diff --git a/trunk/drivers/usb/serial/empeg.c b/trunk/drivers/usb/serial/empeg.c index 1072e847280f..a6ab5b58d9ca 100644 --- a/trunk/drivers/usb/serial/empeg.c +++ b/trunk/drivers/usb/serial/empeg.c @@ -33,8 +33,9 @@ * Moved MOD_DEC_USE_COUNT to end of empeg_close(). * * (12/03/2000) gb - * Added tty->ldisc.set_termios(port, tty, NULL) to empeg_open(). - * This notifies the tty driver that the termios have changed. + * Added port->port.tty->ldisc.set_termios(port->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 @@ -353,7 +354,7 @@ static void empeg_read_bulk_callback(struct urb *urb) usb_serial_debug_data(debug, &port->dev, __func__, urb->actual_length, data); - tty = tty_port_tty_get(&port->port); + tty = port->port.tty; if (urb->actual_length) { tty_buffer_request_room(tty, urb->actual_length); @@ -361,7 +362,6 @@ 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( diff --git a/trunk/drivers/usb/serial/ftdi_sio.c b/trunk/drivers/usb/serial/ftdi_sio.c index c2ac129557aa..3dc93b542b30 100644 --- a/trunk/drivers/usb/serial/ftdi_sio.c +++ b/trunk/drivers/usb/serial/ftdi_sio.c @@ -860,7 +860,7 @@ static int update_mctrl(struct usb_serial_port *port, unsigned int set, kfree(buf); if (rv < 0) { - dbg("%s Error from MODEM_CTRL urb: DTR %s, RTS %s", + err("%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 = tty_port_tty_get(&port->port); + tty = port->port.tty; 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__); - goto out; + return; } 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); - goto out; + return; } /* count data bytes, but not status bytes */ @@ -1838,8 +1838,7 @@ 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 */ @@ -1864,7 +1863,7 @@ static void ftdi_process_read(struct work_struct *work) if (port->port.count <= 0) return; - tty = tty_port_tty_get(&port->port); + tty = port->port.tty; if (!tty) { dbg("%s - bad tty pointer - exiting", __func__); return; @@ -1873,13 +1872,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__); - goto out; + return; } urb = port->read_urb; if (!urb) { dbg("%s - bad read_urb pointer - exiting", __func__); - goto out; + return; } data = urb->transfer_buffer; @@ -2021,7 +2020,7 @@ static void ftdi_process_read(struct work_struct *work) schedule_delayed_work(&priv->rx_work, 1); else dbg("%s - port is closed", __func__); - goto out; + return; } /* urb is completely processed */ @@ -2042,8 +2041,6 @@ 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 */ @@ -2259,7 +2256,7 @@ static int ftdi_tiocmget(struct tty_struct *tty, struct file *file) 0, 0, buf, 1, WDR_TIMEOUT); if (ret < 0) { - dbg("%s Could not get modem status of device - err: %d", __func__, + err("%s Could not get modem status of device - err: %d", __func__, ret); return ret; } @@ -2278,7 +2275,7 @@ static int ftdi_tiocmget(struct tty_struct *tty, struct file *file) 0, priv->interface, buf, 2, WDR_TIMEOUT); if (ret < 0) { - dbg("%s Could not get modem status of device - err: %d", __func__, + err("%s Could not get modem status of device - err: %d", __func__, ret); return ret; } diff --git a/trunk/drivers/usb/serial/garmin_gps.c b/trunk/drivers/usb/serial/garmin_gps.c index 2ad0569bcf19..d95382088075 100644 --- a/trunk/drivers/usb/serial/garmin_gps.c +++ b/trunk/drivers/usb/serial/garmin_gps.c @@ -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 = tty_port_tty_get(&port->port); + struct tty_struct *tty = port->port.tty; if (tty && actual_length) { @@ -287,7 +287,6 @@ 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); } diff --git a/trunk/drivers/usb/serial/generic.c b/trunk/drivers/usb/serial/generic.c index 814909f1ee63..fe84c88ec20c 100644 --- a/trunk/drivers/usb/serial/generic.c +++ b/trunk/drivers/usb/serial/generic.c @@ -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 = tty_port_tty_get(&port->port); + struct tty_struct *tty = port->port.tty; int room; /* Push data to tty */ @@ -341,7 +341,6 @@ 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); } diff --git a/trunk/drivers/usb/serial/io_edgeport.c b/trunk/drivers/usb/serial/io_edgeport.c index 611f97fd62f1..bfa508ddb0fe 100644 --- a/trunk/drivers/usb/serial/io_edgeport.c +++ b/trunk/drivers/usb/serial/io_edgeport.c @@ -600,7 +600,6 @@ 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; @@ -676,12 +675,9 @@ static void edge_interrupt_callback(struct urb *urb) /* tell the tty driver that something has changed */ - tty = tty_port_tty_get( - &edge_port->port->port); - if (tty) { - tty_wakeup(tty); - tty_kref_put(tty); - } + if (edge_port->port->port.tty) + tty_wakeup(edge_port->port->port.tty); + /* Since we have more credit, check if more data can be sent */ send_more_port_data(edge_serial, @@ -782,14 +778,13 @@ static void edge_bulk_out_data_callback(struct urb *urb) __func__, status); } - tty = tty_port_tty_get(&edge_port->port->port); + tty = edge_port->port->port.tty; 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; @@ -831,12 +826,11 @@ static void edge_bulk_out_cmd_callback(struct urb *urb) } /* Get pointer to tty */ - tty = tty_port_tty_get(&edge_port->port->port); + tty = edge_port->port->port.tty; /* 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; @@ -1938,13 +1932,11 @@ 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 = tty_port_tty_get( - &edge_port->port->port); + tty = edge_port->port->port.tty; 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; } @@ -1979,7 +1971,6 @@ 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 */ @@ -2029,12 +2020,10 @@ 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 */ - tty = tty_port_tty_get(&edge_port->port->port); - if (tty) { - change_port_settings(tty, - edge_port, tty->termios); - tty_kref_put(tty); - } + /* 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); /* we have completed the open */ edge_port->openPending = false; @@ -2174,14 +2163,10 @@ static void handle_new_lsr(struct edgeport_port *edge_port, __u8 lsrData, } /* Place LSR data byte into Rx buffer */ - 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); - } - } + if (lsrData && edge_port->port->port.tty) + edge_tty_recv(&edge_port->port->dev, + edge_port->port->port.tty, &data, 1); + /* update input line counters */ icount = &edge_port->icount; if (newLsr & LSR_BREAK) diff --git a/trunk/drivers/usb/serial/io_ti.c b/trunk/drivers/usb/serial/io_ti.c index 541dd8e6e7a2..cb4c54316cf5 100644 --- a/trunk/drivers/usb/serial/io_ti.c +++ b/trunk/drivers/usb/serial/io_ti.c @@ -572,7 +572,7 @@ static void chase_port(struct edgeport_port *port, unsigned long timeout, int flush) { int baud_rate; - struct tty_struct *tty = tty_port_tty_get(&port->port->port); + struct tty_struct *tty = port->port->port.tty; wait_queue_t wait; unsigned long flags; @@ -599,7 +599,6 @@ 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; @@ -1555,7 +1554,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 = tty_port_tty_get(&edge_port->port->port); + tty = edge_port->port->port.tty; /* handle CTS flow control */ if (tty && C_CRTSCTS(tty)) { if (msr & EDGEPORT_MSR_CTS) { @@ -1565,7 +1564,6 @@ static void handle_new_msr(struct edgeport_port *edge_port, __u8 msr) tty->hw_stopped = 1; } } - tty_kref_put(tty); return; } @@ -1576,7 +1574,6 @@ 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); @@ -1590,13 +1587,8 @@ 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) { - 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); - } - } + if (lsr_data && edge_port->port->port.tty) + edge_tty_recv(&edge_port->port->dev, edge_port->port->port.tty, &data, 1); /* update input line counters */ icount = &edge_port->icount; @@ -1757,7 +1749,7 @@ static void edge_bulk_in_callback(struct urb *urb) ++data; } - tty = tty_port_tty_get(&edge_port->port->port); + tty = edge_port->port->port.tty; if (tty && urb->actual_length) { usb_serial_debug_data(debug, &edge_port->port->dev, __func__, urb->actual_length, data); @@ -1769,7 +1761,6 @@ 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 */ @@ -1805,7 +1796,6 @@ 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); @@ -1828,9 +1818,7 @@ static void edge_bulk_out_callback(struct urb *urb) } /* send any buffered data */ - tty = tty_port_tty_get(&port->port); - edge_send(tty); - tty_kref_put(tty); + edge_send(port->port.tty); } static int edge_open(struct tty_struct *tty, @@ -1888,7 +1876,7 @@ static int edge_open(struct tty_struct *tty, /* set up the port settings */ if (tty) - edge_set_termios(tty, port, tty->termios); + edge_set_termios(tty, port, port->port.tty->termios); /* open up the port */ diff --git a/trunk/drivers/usb/serial/ipaq.c b/trunk/drivers/usb/serial/ipaq.c index 2affa9c118b2..cd9a2e138c8b 100644 --- a/trunk/drivers/usb/serial/ipaq.c +++ b/trunk/drivers/usb/serial/ipaq.c @@ -764,14 +764,13 @@ static void ipaq_read_bulk_callback(struct urb *urb) usb_serial_debug_data(debug, &port->dev, __func__, urb->actual_length, data); - tty = tty_port_tty_get(&port->port); + tty = port->port.tty; 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, diff --git a/trunk/drivers/usb/serial/ipw.c b/trunk/drivers/usb/serial/ipw.c index 480cac27d646..a842025b9b57 100644 --- a/trunk/drivers/usb/serial/ipw.c +++ b/trunk/drivers/usb/serial/ipw.c @@ -170,13 +170,12 @@ static void ipw_read_bulk_callback(struct urb *urb) usb_serial_debug_data(debug, &port->dev, __func__, urb->actual_length, data); - tty = tty_port_tty_get(&port->port); + tty = port->port.tty; 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, diff --git a/trunk/drivers/usb/serial/ir-usb.c b/trunk/drivers/usb/serial/ir-usb.c index 45d4043e04ab..e59155c6607d 100644 --- a/trunk/drivers/usb/serial/ir-usb.c +++ b/trunk/drivers/usb/serial/ir-usb.c @@ -465,12 +465,11 @@ 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 = tty_port_tty_get(&port->port); + tty = port->port.tty; 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. diff --git a/trunk/drivers/usb/serial/iuu_phoenix.c b/trunk/drivers/usb/serial/iuu_phoenix.c index 53710aa7eadd..ddff37fa6339 100644 --- a/trunk/drivers/usb/serial/iuu_phoenix.c +++ b/trunk/drivers/usb/serial/iuu_phoenix.c @@ -629,14 +629,13 @@ static void read_buf_callback(struct urb *urb) } dbg("%s - %i chars to write", __func__, urb->actual_length); - tty = tty_port_tty_get(&port->port); + tty = port->port.tty; 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); } diff --git a/trunk/drivers/usb/serial/keyspan.c b/trunk/drivers/usb/serial/keyspan.c index 15447af48691..704716f6f6d3 100644 --- a/trunk/drivers/usb/serial/keyspan.c +++ b/trunk/drivers/usb/serial/keyspan.c @@ -430,7 +430,7 @@ static void usa26_indat_callback(struct urb *urb) } port = urb->context; - tty = tty_port_tty_get(&port->port); + tty = port->port.tty; if (tty && urb->actual_length) { /* 0x80 bit is error flag */ if ((data[0] & 0x80) == 0) { @@ -459,7 +459,6 @@ 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; @@ -514,7 +513,6 @@ 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; @@ -555,11 +553,12 @@ 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 (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); + 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); */ } /* Resubmit urb so we continue receiving */ @@ -605,12 +604,11 @@ static void usa28_indat_callback(struct urb *urb) p_priv = usb_get_serial_port_data(port); data = urb->transfer_buffer; - tty =tty_port_tty_get(&port->port); - if (tty && urb->actual_length) { + tty = port->port.tty; + if (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; @@ -654,7 +652,6 @@ 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; @@ -692,11 +689,12 @@ 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( 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); + 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); */ } /* Resubmit urb so we continue receiving */ @@ -787,11 +785,12 @@ 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 (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); + 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); */ } /* Resubmit urb so we continue receiving */ @@ -828,7 +827,7 @@ static void usa49_indat_callback(struct urb *urb) } port = urb->context; - tty = tty_port_tty_get(&port->port); + tty = port->port.tty; if (tty && urb->actual_length) { /* 0x80 bit is error flag */ if ((data[0] & 0x80) == 0) { @@ -851,7 +850,6 @@ 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; @@ -895,7 +893,7 @@ static void usa49wg_indat_callback(struct urb *urb) return; } port = serial->port[data[i++]]; - tty = tty_port_tty_get(&port->port); + tty = port->port.tty; len = data[i++]; /* 0x80 bit is error flag */ @@ -929,7 +927,6 @@ static void usa49wg_indat_callback(struct urb *urb) } if (port->port.count) tty_flip_buffer_push(tty); - tty_kref_put(tty); } } @@ -970,8 +967,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 */ @@ -1007,7 +1004,6 @@ static void usa90_indat_callback(struct urb *urb) } } tty_flip_buffer_push(tty); - tty_kref_put(tty); } /* Resubmit urb so we continue receiving */ @@ -1029,7 +1025,6 @@ 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; @@ -1058,11 +1053,12 @@ 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 (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); + 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); */ } /* Resubmit urb so we continue receiving */ @@ -1134,11 +1130,12 @@ 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 (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); + 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); */ } /* Resubmit urb so we continue receiving */ @@ -1335,7 +1332,7 @@ static void keyspan_close(struct tty_struct *tty, stop_urb(p_priv->out_urbs[i]); } } - tty_port_tty_set(&port->port, NULL); + port->port.tty = NULL; } /* download the firmware to a pre-renumeration device */ diff --git a/trunk/drivers/usb/serial/keyspan_pda.c b/trunk/drivers/usb/serial/keyspan_pda.c index 99e9a14c5bf6..040040a267d9 100644 --- a/trunk/drivers/usb/serial/keyspan_pda.c +++ b/trunk/drivers/usb/serial/keyspan_pda.c @@ -172,9 +172,8 @@ 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; - struct tty_struct *tty = tty_port_tty_get(&port->port); - tty_wakeup(tty); - tty_kref_put(tty); + + tty_wakeup(port->port.tty); } static void keyspan_pda_request_unthrottle(struct work_struct *work) @@ -206,7 +205,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 = tty_port_tty_get(&port->port); + struct tty_struct *tty = port->port.tty; unsigned char *data = urb->transfer_buffer; int retval; int status = urb->status; @@ -223,7 +222,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); - goto out; + return; default: dbg("%s - nonzero urb status received: %d", __func__, status); @@ -262,11 +261,8 @@ static void keyspan_pda_rx_interrupt(struct urb *urb) exit: retval = usb_submit_urb(urb, GFP_ATOMIC); if (retval) - dev_err(&port->dev, - "%s - usb_submit_urb failed with result %d", - __func__, retval); -out: - tty_kref_put(tty); + err("%s - usb_submit_urb failed with result %d", + __func__, retval); } diff --git a/trunk/drivers/usb/serial/kl5kusb105.c b/trunk/drivers/usb/serial/kl5kusb105.c index ff3a07f5102f..b84dddc71124 100644 --- a/trunk/drivers/usb/serial/kl5kusb105.c +++ b/trunk/drivers/usb/serial/kl5kusb105.c @@ -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 = tty_port_tty_get(&port->port); + tty = port->port.tty; /* 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,7 +679,6 @@ 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; diff --git a/trunk/drivers/usb/serial/kobil_sct.c b/trunk/drivers/usb/serial/kobil_sct.c index cfcf37c2b957..deba28ec77e8 100644 --- a/trunk/drivers/usb/serial/kobil_sct.c +++ b/trunk/drivers/usb/serial/kobil_sct.c @@ -383,7 +383,7 @@ static void kobil_read_int_callback(struct urb *urb) return; } - tty = tty_port_tty_get(&port->port); + tty = port->port.tty; if (urb->actual_length) { /* BEGIN DEBUG */ @@ -405,7 +405,6 @@ 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; diff --git a/trunk/drivers/usb/serial/mct_u232.c b/trunk/drivers/usb/serial/mct_u232.c index 9b2cef81cde0..0ded8bd6ec85 100644 --- a/trunk/drivers/usb/serial/mct_u232.c +++ b/trunk/drivers/usb/serial/mct_u232.c @@ -563,11 +563,10 @@ 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 = tty_port_tty_get(&port->port); + tty = port->port.tty; if (urb->actual_length) { tty_insert_flip_string(tty, data, urb->actual_length); tty_flip_buffer_push(tty); - tty_kref_put(tty); } goto exit; } @@ -592,7 +591,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 = tty_port_tty_get(&port->port); + tty = port->port.tty; /* Overrun Error */ if (priv->last_lsr & MCT_U232_LSR_OE) { } @@ -605,7 +604,6 @@ 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); diff --git a/trunk/drivers/usb/serial/mos7720.c b/trunk/drivers/usb/serial/mos7720.c index 7b538caec37f..7c4917d77c0a 100644 --- a/trunk/drivers/usb/serial/mos7720.c +++ b/trunk/drivers/usb/serial/mos7720.c @@ -216,13 +216,12 @@ static void mos7720_bulk_in_callback(struct urb *urb) data = urb->transfer_buffer; - tty = tty_port_tty_get(&port->port); + tty = port->port.tty; 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 !!!"); @@ -263,11 +262,10 @@ static void mos7720_bulk_out_data_callback(struct urb *urb) dbg("Entering ........."); - tty = tty_port_tty_get(&mos7720_port->port->port); + tty = mos7720_port->port->port.tty; if (tty && mos7720_port->open) tty_wakeup(tty); - tty_kref_put(tty); } /* @@ -1269,6 +1267,29 @@ 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) { @@ -1388,6 +1409,13 @@ 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, diff --git a/trunk/drivers/usb/serial/mos7840.c b/trunk/drivers/usb/serial/mos7840.c index 60543d79ef56..09d82062b973 100644 --- a/trunk/drivers/usb/serial/mos7840.c +++ b/trunk/drivers/usb/serial/mos7840.c @@ -709,13 +709,12 @@ static void mos7840_bulk_in_callback(struct urb *urb) dbg("%s", "Entering ........... \n"); if (urb->actual_length) { - tty = tty_port_tty_get(&mos7840_port->port->port); + tty = mos7840_port->port->port.tty; 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(); @@ -774,10 +773,10 @@ static void mos7840_bulk_out_data_callback(struct urb *urb) dbg("%s \n", "Entering ........."); - tty = tty_port_tty_get(&mos7840_port->port->port); + tty = mos7840_port->port->port.tty; + if (tty && mos7840_port->open) tty_wakeup(tty); - tty_kref_put(tty); } diff --git a/trunk/drivers/usb/serial/navman.c b/trunk/drivers/usb/serial/navman.c index bcdcbb822705..d6736531a0fa 100644 --- a/trunk/drivers/usb/serial/navman.c +++ b/trunk/drivers/usb/serial/navman.c @@ -64,13 +64,12 @@ static void navman_read_int_callback(struct urb *urb) usb_serial_debug_data(debug, &port->dev, __func__, urb->actual_length, data); - tty = tty_port_tty_get(&port->port); + tty = port->port.tty; 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); diff --git a/trunk/drivers/usb/serial/omninet.c b/trunk/drivers/usb/serial/omninet.c index c4d70b0f1e48..ae8e227f3db2 100644 --- a/trunk/drivers/usb/serial/omninet.c +++ b/trunk/drivers/usb/serial/omninet.c @@ -172,7 +172,7 @@ static int omninet_open(struct tty_struct *tty, dbg("%s - port %d", __func__, port->number); wport = serial->port[1]; - tty_port_tty_set(&wport->port, tty); + wport->port.tty = tty; /* FIXME */ /* Start reading from the device */ usb_fill_bulk_urb(port->read_urb, serial->dev, @@ -229,11 +229,9 @@ static void omninet_read_bulk_callback(struct urb *urb) } if (urb->actual_length && header->oh_len) { - 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); + tty_insert_flip_string(port->port.tty, + data + OMNINET_DATAOFFSET, header->oh_len); + tty_flip_buffer_push(port->port.tty); } /* Continue trying to always read */ diff --git a/trunk/drivers/usb/serial/option.c b/trunk/drivers/usb/serial/option.c index 6b1727e751e3..73f8277f88f2 100644 --- a/trunk/drivers/usb/serial/option.c +++ b/trunk/drivers/usb/serial/option.c @@ -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 = tty_port_tty_get(&port->port); + tty = port->port.tty; 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,13 +647,9 @@ static void option_instat_callback(struct urb *urb) portdata->dsr_state = ((signals & 0x02) ? 1 : 0); portdata->ri_state = ((signals & 0x08) ? 1 : 0); - 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); - } + if (port->port.tty && !C_CLOCAL(port->port.tty) && + old_dcd_state && !portdata->dcd_state) + tty_hangup(port->port.tty); } else { dbg("%s: type %x req %x", __func__, req_pkt->bRequestType, req_pkt->bRequest); @@ -797,7 +793,7 @@ static void option_close(struct tty_struct *tty, for (i = 0; i < N_OUT_URB; i++) usb_kill_urb(portdata->out_urbs[i]); } - tty_port_tty_set(&port->port, NULL); + port->port.tty = NULL; /* FIXME */ } /* Helper functions used by option_setup_urbs */ diff --git a/trunk/drivers/usb/serial/oti6858.c b/trunk/drivers/usb/serial/oti6858.c index ba551f00f16f..81db5715ee25 100644 --- a/trunk/drivers/usb/serial/oti6858.c +++ b/trunk/drivers/usb/serial/oti6858.c @@ -224,6 +224,10 @@ 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, @@ -998,12 +1002,11 @@ static void oti6858_read_bulk_callback(struct urb *urb) return; } - tty = tty_port_tty_get(&port->port); + tty = port->port.tty; 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) { diff --git a/trunk/drivers/usb/serial/pl2303.c b/trunk/drivers/usb/serial/pl2303.c index 908437847165..1ede1441cb1b 100644 --- a/trunk/drivers/usb/serial/pl2303.c +++ b/trunk/drivers/usb/serial/pl2303.c @@ -154,6 +154,7 @@ struct pl2303_private { wait_queue_head_t delta_msr_wait; u8 line_control; u8 line_status; + u8 termios_initialized; enum pl2303_type type; }; @@ -525,6 +526,16 @@ 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 */ @@ -1046,7 +1057,7 @@ static void pl2303_read_bulk_callback(struct urb *urb) tty_flag = TTY_FRAME; dbg("%s - tty_flag = %d", __func__, tty_flag); - tty = tty_port_tty_get(&port->port); + tty = port->port.tty; if (tty && urb->actual_length) { tty_buffer_request_room(tty, urb->actual_length + 1); /* overrun is special, not associated with a char */ @@ -1056,7 +1067,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; diff --git a/trunk/drivers/usb/serial/safe_serial.c b/trunk/drivers/usb/serial/safe_serial.c index 72903ac9f5c0..def52d07a4ea 100644 --- a/trunk/drivers/usb/serial/safe_serial.c +++ b/trunk/drivers/usb/serial/safe_serial.c @@ -217,7 +217,6 @@ 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; @@ -243,7 +242,6 @@ 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); @@ -252,9 +250,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(tty, + tty_insert_flip_string(port->port.tty, data, actual_length); - tty_flip_buffer_push(tty); + tty_flip_buffer_push(port->port.tty); } else { err("%s - inconsistent lengths %d:%d", __func__, actual_length, length); @@ -263,10 +261,9 @@ static void safe_read_bulk_callback(struct urb *urb) err("%s - bad CRC %x", __func__, fcs); } } else { - tty_insert_flip_string(tty, data, length); - tty_flip_buffer_push(tty); + tty_insert_flip_string(port->port.tty, data, length); + tty_flip_buffer_push(port->port.tty); } - tty_kref_put(tty); /* Continue trying to always read */ usb_fill_bulk_urb(urb, port->serial->dev, diff --git a/trunk/drivers/usb/serial/sierra.c b/trunk/drivers/usb/serial/sierra.c index 8b9eaf383679..ea1a103c99be 100644 --- a/trunk/drivers/usb/serial/sierra.c +++ b/trunk/drivers/usb/serial/sierra.c @@ -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); - tty_kref_put(tty); - } else + } else { dbg("%s: empty read urb received", __func__); + } /* Resubmit urb so we continue receiving */ if (port->port.count && status != -ESHUTDOWN) { @@ -485,7 +485,6 @@ 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); @@ -495,11 +494,9 @@ static void sierra_instat_callback(struct urb *urb) portdata->dsr_state = ((signals & 0x02) ? 1 : 0); portdata->ri_state = ((signals & 0x08) ? 1 : 0); - tty = tty_port_tty_get(&port->port); - if (tty && !C_CLOCAL(tty) && + if (port->port.tty && !C_CLOCAL(port->port.tty) && old_dcd_state && !portdata->dcd_state) - tty_hangup(tty); - tty_kref_put(tty); + tty_hangup(port->port.tty); } else { dbg("%s: type %x req %x", __func__, req_pkt->bRequestType, req_pkt->bRequest); @@ -619,7 +616,8 @@ static void sierra_close(struct tty_struct *tty, } usb_kill_urb(port->interrupt_in_urb); - tty_port_tty_set(&port->port, NULL); + + port->port.tty = NULL; /* FIXME */ } static int sierra_startup(struct usb_serial *serial) diff --git a/trunk/drivers/usb/serial/spcp8x5.c b/trunk/drivers/usb/serial/spcp8x5.c index 1533d6e12238..283cf6b36b2c 100644 --- a/trunk/drivers/usb/serial/spcp8x5.c +++ b/trunk/drivers/usb/serial/spcp8x5.c @@ -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 = tty_port_tty_get(&port->port); + tty = port->port.tty; if (tty && urb->actual_length) { tty_buffer_request_room(tty, urb->actual_length + 1); /* overrun is special, not associated with a char */ @@ -765,7 +765,6 @@ 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) { diff --git a/trunk/drivers/usb/serial/ti_usb_3410_5052.c b/trunk/drivers/usb/serial/ti_usb_3410_5052.c index c90237d48b0e..9a3e495c769c 100644 --- a/trunk/drivers/usb/serial/ti_usb_3410_5052.c +++ b/trunk/drivers/usb/serial/ti_usb_3410_5052.c @@ -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 tty_struct *tty, struct ti_port *tport, +static int ti_set_serial_info(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(tty, tport, - (struct serial_struct __user *)arg); + return ti_set_serial_info(tport, + (struct serial_struct __user *)arg); case TIOCMIWAIT: dbg("%s - (%d) TIOCMIWAIT", __func__, port->number); cprev = tport->tp_icount; @@ -1211,7 +1211,6 @@ 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__); @@ -1240,22 +1239,20 @@ static void ti_bulk_in_callback(struct urb *urb) return; } - tty = tty_port_tty_get(&port->port); - if (tty && urb->actual_length) { + if (port->port.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, tty, + ti_recv(&urb->dev->dev, port->port.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: @@ -1333,7 +1330,7 @@ static void ti_send(struct ti_port *tport) { int count, result; struct usb_serial_port *port = tport->tp_port; - struct tty_struct *tty = tty_port_tty_get(&port->port); /* FIXME */ + struct tty_struct *tty = port->port.tty; /* FIXME */ unsigned long flags; @@ -1341,15 +1338,19 @@ static void ti_send(struct ti_port *tport) spin_lock_irqsave(&tport->tp_lock, flags); - if (tport->tp_write_urb_in_use) - goto unlock; + if (tport->tp_write_urb_in_use) { + spin_unlock_irqrestore(&tport->tp_lock, flags); + return; + } count = ti_buf_get(tport->tp_write_buf, port->write_urb->transfer_buffer, port->bulk_out_size); - if (count == 0) - goto unlock; + if (count == 0) { + spin_unlock_irqrestore(&tport->tp_lock, flags); + return; + } tport->tp_write_urb_in_use = 1; @@ -1379,13 +1380,7 @@ 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; } @@ -1469,16 +1464,20 @@ static int ti_get_serial_info(struct ti_port *tport, } -static int ti_set_serial_info(struct tty_struct *tty, struct ti_port *tport, +static int ti_set_serial_info(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; - tty->low_latency = (tport->tp_flags & ASYNC_LOW_LATENCY) ? 1 : 0; + /* FIXME */ + if (port->port.tty) + port->port.tty->low_latency = + (tport->tp_flags & ASYNC_LOW_LATENCY) ? 1 : 0; tport->tp_closing_wait = new_serial.closing_wait; return 0; @@ -1511,7 +1510,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 = tty_port_tty_get(&tport->tp_port->port); + tty = tport->tp_port->port.tty; if (tty && C_CRTSCTS(tty)) { if (msr & TI_MSR_CTS) { tty->hw_stopped = 0; @@ -1520,7 +1519,6 @@ static void ti_handle_new_msr(struct ti_port *tport, __u8 msr) tty->hw_stopped = 1; } } - tty_kref_put(tty); } diff --git a/trunk/drivers/usb/serial/usb-serial.c b/trunk/drivers/usb/serial/usb-serial.c index e7d4246027b2..4f7f9e3ae0a4 100644 --- a/trunk/drivers/usb/serial/usb-serial.c +++ b/trunk/drivers/usb/serial/usb-serial.c @@ -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; - tty_port_tty_set(&port->port, tty); + port->port.tty = tty; if (port->port.count == 1) { @@ -246,7 +246,7 @@ static int serial_open (struct tty_struct *tty, struct file *filp) bailout_mutex_unlock: port->port.count = 0; tty->driver_data = NULL; - tty_port_tty_set(&port->port, NULL); + port->port.tty = NULL; mutex_unlock(&port->mutex); bailout_kref_put: usb_serial_put(serial); @@ -276,11 +276,10 @@ 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)) { - 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); + if (port->port.tty) { + if (port->port.tty->driver_data) + port->port.tty->driver_data = NULL; + port->port.tty = NULL; } } @@ -509,12 +508,11 @@ static void usb_serial_port_work(struct work_struct *work) if (!port) return; - tty = tty_port_tty_get(&port->port); + tty = port->port.tty; if (!tty) return; tty_wakeup(tty); - tty_kref_put(tty); } static void port_release(struct device *dev) @@ -821,7 +819,6 @@ 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); @@ -1043,11 +1040,8 @@ void usb_serial_disconnect(struct usb_interface *interface) for (i = 0; i < serial->num_ports; ++i) { port = serial->port[i]; if (port) { - struct tty_struct *tty = tty_port_tty_get(&port->port); - if (tty) { - tty_hangup(tty); - tty_kref_put(tty); - } + if (port->port.tty) + tty_hangup(port->port.tty); kill_traffic(port); } } diff --git a/trunk/drivers/usb/serial/visor.c b/trunk/drivers/usb/serial/visor.c index a6d1c75a1c89..cf8924f9a2cc 100644 --- a/trunk/drivers/usb/serial/visor.c +++ b/trunk/drivers/usb/serial/visor.c @@ -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 = 0; + int available_room; dbg("%s - port %d", __func__, port->number); @@ -512,17 +512,13 @@ static void visor_read_bulk_callback(struct urb *urb) usb_serial_debug_data(debug, &port->dev, __func__, urb->actual_length, data); - if (urb->actual_length) { - tty = tty_port_tty_get(&port->port); - if (tty) { - available_room = tty_buffer_request_room(tty, + tty = port->port.tty; + if (tty && urb->actual_length) { + 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); - } - tty_kref_put(tty); + if (available_room) { + tty_insert_flip_string(tty, data, available_room); + tty_flip_buffer_push(tty); } spin_lock(&priv->lock); priv->bytes_in += available_room; diff --git a/trunk/drivers/usb/serial/whiteheat.c b/trunk/drivers/usb/serial/whiteheat.c index 11c8b97a5177..3a9d14384a43 100644 --- a/trunk/drivers/usb/serial/whiteheat.c +++ b/trunk/drivers/usb/serial/whiteheat.c @@ -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 = tty_port_tty_get(&port->port); + struct tty_struct *tty = port->port.tty; 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); - goto out; + return; } 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); - goto out; + return; } tty_insert_flip_string(tty, urb->transfer_buffer, len); sent += len; @@ -1536,8 +1536,6 @@ static void rx_data_softint(struct work_struct *work) if (sent) tty_flip_buffer_push(tty); -out: - tty_kref_put(tty); } diff --git a/trunk/drivers/video/backlight/mbp_nvidia_bl.c b/trunk/drivers/video/backlight/mbp_nvidia_bl.c index 06964af761c6..385cba40ea87 100644 --- a/trunk/drivers/video/backlight/mbp_nvidia_bl.c +++ b/trunk/drivers/video/backlight/mbp_nvidia_bl.c @@ -111,4 +111,6 @@ module_exit(mbp_exit); MODULE_AUTHOR("Matthew Garrett "); MODULE_DESCRIPTION("Nvidia-based Macbook Pro Backlight Driver"); MODULE_LICENSE("GPL"); -MODULE_DEVICE_TABLE(dmi, mbp_device_table); +MODULE_ALIAS("svnAppleInc.:pnMacBookPro3,1"); +MODULE_ALIAS("svnAppleInc.:pnMacBookPro3,2"); +MODULE_ALIAS("svnAppleInc.:pnMacBookPro4,1"); diff --git a/trunk/fs/Kconfig.binfmt b/trunk/fs/Kconfig.binfmt index 17c9c5ec14c5..4a551af6f3fc 100644 --- a/trunk/fs/Kconfig.binfmt +++ b/trunk/fs/Kconfig.binfmt @@ -59,12 +59,10 @@ 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 HAVE_AOUT + depends on ARCH_SUPPORTS_AOUT && \ + (X86_32 || ALPHA || ARM || M68K) ---help--- A.out (Assembler.OUTput) is a set of formats for libraries and executables used in the earliest versions of UNIX. Linux used diff --git a/trunk/fs/debugfs/inode.c b/trunk/fs/debugfs/inode.c index 3dbe2169cf36..08e28c9bb416 100644 --- a/trunk/fs/debugfs/inode.c +++ b/trunk/fs/debugfs/inode.c @@ -26,7 +26,8 @@ #include #include #include -#include + +#define DEBUGFS_MAGIC 0x64626720 static struct vfsmount *debugfs_mount; static int debugfs_mount_count; diff --git a/trunk/fs/devpts/inode.c b/trunk/fs/devpts/inode.c index a70d5d0890c7..488eb424f662 100644 --- a/trunk/fs/devpts/inode.c +++ b/trunk/fs/devpts/inode.c @@ -27,7 +27,6 @@ #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); @@ -170,7 +169,15 @@ static struct file_system_type devpts_fs_type = { * to the System V naming convention */ -int devpts_new_index(struct inode *ptmx_inode) +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 index; int ida_ret; @@ -198,21 +205,20 @@ int devpts_new_index(struct inode *ptmx_inode) return index; } -void devpts_kill_index(struct inode *ptmx_inode, int idx) +void devpts_kill_index(int idx) { mutex_lock(&allocated_ptys_lock); ida_remove(&allocated_ptys, idx); mutex_unlock(&allocated_ptys_lock); } -int devpts_pty_new(struct inode *ptmx_inode, struct tty_struct *tty) +int devpts_pty_new(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); @@ -227,15 +233,10 @@ int devpts_pty_new(struct inode *ptmx_inode, 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; - 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); + dentry = get_node(number); + if (!IS_ERR(dentry) && !dentry->d_inode) { + d_instantiate(dentry, inode); fsnotify_create(devpts_root->d_inode, dentry); } @@ -244,31 +245,36 @@ int devpts_pty_new(struct inode *ptmx_inode, struct tty_struct *tty) return 0; } -struct tty_struct *devpts_get_tty(struct inode *pts_inode, int number) +struct tty_struct *devpts_get_tty(int number) { - BUG_ON(pts_inode->i_rdev == MKDEV(TTYAUX_MAJOR, PTMX_MINOR)); + struct dentry *dentry = get_node(number); + struct tty_struct *tty; - if (pts_inode->i_sb->s_magic == DEVPTS_SUPER_MAGIC) - return (struct tty_struct *)pts_inode->i_private; - return NULL; -} + tty = NULL; + if (!IS_ERR(dentry)) { + if (dentry->d_inode) + tty = dentry->d_inode->i_private; + dput(dentry); + } -void devpts_pty_kill(struct tty_struct *tty) -{ - struct inode *inode = tty->driver_data; - struct dentry *dentry; + mutex_unlock(&devpts_root->d_inode->i_mutex); - BUG_ON(inode->i_rdev == MKDEV(TTYAUX_MAJOR, PTMX_MINOR)); + return tty; +} - mutex_lock(&devpts_root->d_inode->i_mutex); +void devpts_pty_kill(int number) +{ + struct dentry *dentry = get_node(number); - dentry = d_find_alias(inode); - if (dentry && !IS_ERR(dentry)) { - inode->i_nlink--; - d_delete(dentry); + if (!IS_ERR(dentry)) { + struct inode *inode = dentry->d_inode; + if (inode) { + inode->i_nlink--; + d_delete(dentry); + dput(dentry); + } dput(dentry); } - mutex_unlock(&devpts_root->d_inode->i_mutex); } diff --git a/trunk/fs/dquot.c b/trunk/fs/dquot.c index ad7e59003e04..8ec4d6cc7633 100644 --- a/trunk/fs/dquot.c +++ b/trunk/fs/dquot.c @@ -895,9 +895,10 @@ 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) - return; + goto out_lock; tty_write_message(tty, dquot->dq_sb->s_id); if (warntype == QUOTA_NL_ISOFTWARN || warntype == QUOTA_NL_BSOFTWARN) tty_write_message(tty, ": warning, "); @@ -925,7 +926,8 @@ static void print_warning(struct dquot *dquot, const int warntype) break; } tty_write_message(tty, msg); - tty_kref_put(tty); +out_lock: + mutex_unlock(&tty_mutex); } #endif diff --git a/trunk/fs/efs/super.c b/trunk/fs/efs/super.c index 73b19cfc91fc..567b134fa1f1 100644 --- a/trunk/fs/efs/super.c +++ b/trunk/fs/efs/super.c @@ -341,6 +341,8 @@ 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; diff --git a/trunk/fs/open.c b/trunk/fs/open.c index 5596049863bf..07da9359481c 100644 --- a/trunk/fs/open.c +++ b/trunk/fs/open.c @@ -1141,7 +1141,8 @@ EXPORT_SYMBOL(sys_close); asmlinkage long sys_vhangup(void) { if (capable(CAP_SYS_TTY_CONFIG)) { - tty_vhangup_self(); + /* XXX: this needs locking */ + tty_vhangup(current->signal->tty); return 0; } return -EPERM; diff --git a/trunk/fs/proc/Kconfig b/trunk/fs/proc/Kconfig index 50f8f0600f06..73cd7a418f06 100644 --- a/trunk/fs/proc/Kconfig +++ b/trunk/fs/proc/Kconfig @@ -57,13 +57,3 @@ 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. diff --git a/trunk/fs/proc/array.c b/trunk/fs/proc/array.c index f4bc0e789539..71c9be59c9c2 100644 --- a/trunk/fs/proc/array.c +++ b/trunk/fs/proc/array.c @@ -86,6 +86,11 @@ #include #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; @@ -256,6 +261,7 @@ 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; @@ -266,6 +272,7 @@ 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); diff --git a/trunk/fs/proc/base.c b/trunk/fs/proc/base.c index b5918ae8ca79..a28840b11b89 100644 --- a/trunk/fs/proc/base.c +++ b/trunk/fs/proc/base.c @@ -148,6 +148,9 @@ 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; @@ -161,6 +164,7 @@ 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; @@ -467,10 +471,14 @@ static int proc_pid_limits(struct task_struct *task, char *buffer) struct rlimit rlim[RLIM_NLIMITS]; - if (!lock_task_sighand(task, &flags)) + rcu_read_lock(); + if (!lock_task_sighand(task,&flags)) { + rcu_read_unlock(); return 0; + } memcpy(rlim, task->signal->rlim, sizeof(struct rlimit) * RLIM_NLIMITS); unlock_task_sighand(task, &flags); + rcu_read_unlock(); /* * print the file header @@ -2435,13 +2443,6 @@ 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 */ @@ -2458,7 +2459,6 @@ 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,7 +2794,6 @@ 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), @@ -3089,7 +3088,9 @@ 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); } diff --git a/trunk/fs/proc/inode.c b/trunk/fs/proc/inode.c index c6b4fa7e3b49..8bb03f056c28 100644 --- a/trunk/fs/proc/inode.c +++ b/trunk/fs/proc/inode.c @@ -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 -EINVAL; + return rv; } pde->pde_users++; open = pde->proc_fops->open; diff --git a/trunk/fs/proc/internal.h b/trunk/fs/proc/internal.h index 3bfb7b8747b3..442202314d53 100644 --- a/trunk/fs/proc/internal.h +++ b/trunk/fs/proc/internal.h @@ -45,6 +45,8 @@ 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, diff --git a/trunk/fs/proc/proc_misc.c b/trunk/fs/proc/proc_misc.c index 66c1ab87656c..29e20c6b1f7f 100644 --- a/trunk/fs/proc/proc_misc.c +++ b/trunk/fs/proc/proc_misc.c @@ -68,6 +68,7 @@ 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) diff --git a/trunk/fs/proc/proc_sysctl.c b/trunk/fs/proc/proc_sysctl.c index 945a81043ba2..f9a8b892718f 100644 --- a/trunk/fs/proc/proc_sysctl.c +++ b/trunk/fs/proc/proc_sysctl.c @@ -66,7 +66,7 @@ static struct ctl_table *find_in_table(struct ctl_table *p, struct qstr *name) return NULL; } -static struct ctl_table_header *grab_header(struct inode *inode) +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; diff --git a/trunk/fs/proc/task_mmu.c b/trunk/fs/proc/task_mmu.c index 4806830ea2a1..73d1891ee625 100644 --- a/trunk/fs/proc/task_mmu.c +++ b/trunk/fs/proc/task_mmu.c @@ -210,6 +210,9 @@ 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; @@ -739,11 +742,22 @@ 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, + .show = show_numa_map_checked }; static int numa_maps_open(struct inode *inode, struct file *file) diff --git a/trunk/fs/proc/task_nommu.c b/trunk/fs/proc/task_nommu.c index 219bd79ea894..5d84e7121df8 100644 --- a/trunk/fs/proc/task_nommu.c +++ b/trunk/fs/proc/task_nommu.c @@ -110,6 +110,11 @@ 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); } diff --git a/trunk/fs/proc/vmcore.c b/trunk/fs/proc/vmcore.c index 841368b87a29..9ac0f5e064e0 100644 --- a/trunk/fs/proc/vmcore.c +++ b/trunk/fs/proc/vmcore.c @@ -165,8 +165,14 @@ 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/trunk/include/asm-cris/a.out.h b/trunk/include/asm-cris/a.out.h new file mode 100644 index 000000000000..c82e9f9b75f6 --- /dev/null +++ b/trunk/include/asm-cris/a.out.h @@ -0,0 +1,26 @@ +#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 diff --git a/trunk/include/asm-generic/statfs.h b/trunk/include/asm-generic/statfs.h index 6129d6802149..1d01043e797d 100644 --- a/trunk/include/asm-generic/statfs.h +++ b/trunk/include/asm-generic/statfs.h @@ -6,64 +6,33 @@ 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 { - __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; + __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; - __statfs_word f_namelen; - __statfs_word f_frsize; - __statfs_word f_spare[5]; + __u32 f_namelen; + __u32 f_frsize; + __u32 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 { - __statfs_word f_type; - __statfs_word f_bsize; + __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; - __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 + __u32 f_namelen; + __u32 f_frsize; + __u32 f_spare[5]; +}; struct compat_statfs64 { __u32 f_type; @@ -77,6 +46,6 @@ struct compat_statfs64 { __u32 f_namelen; __u32 f_frsize; __u32 f_spare[5]; -} ARCH_PACK_COMPAT_STATFS64; +}; #endif diff --git a/trunk/include/asm-m32r/a.out.h b/trunk/include/asm-m32r/a.out.h new file mode 100644 index 000000000000..ab150f5c1666 --- /dev/null +++ b/trunk/include/asm-m32r/a.out.h @@ -0,0 +1,20 @@ +#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/trunk/include/asm-parisc/a.out.h b/trunk/include/asm-parisc/a.out.h new file mode 100644 index 000000000000..eb04e34c5bb1 --- /dev/null +++ b/trunk/include/asm-parisc/a.out.h @@ -0,0 +1,20 @@ +#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__ */ diff --git a/trunk/include/asm-parisc/statfs.h b/trunk/include/asm-parisc/statfs.h index 324bea905dc6..1d2b8130b23d 100644 --- a/trunk/include/asm-parisc/statfs.h +++ b/trunk/include/asm-parisc/statfs.h @@ -1,7 +1,58 @@ #ifndef _PARISC_STATFS_H #define _PARISC_STATFS_H -#define __statfs_word long -#include +#ifndef __KERNEL_STRICT_NAMES + +#include + +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]; +}; #endif diff --git a/trunk/include/asm-x86/desc.h b/trunk/include/asm-x86/desc.h index f06adac7938c..ebc307817e98 100644 --- a/trunk/include/asm-x86/desc.h +++ b/trunk/include/asm-x86/desc.h @@ -351,16 +351,20 @@ 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_system_trap_gate(unsigned int n, void *addr) +static inline void set_trap_gate(unsigned int n, void *addr) { BUG_ON((unsigned)n > 0xFF); - _set_gate(n, GATE_TRAP, addr, 0x3, 0, __KERNEL_CS); + _set_gate(n, GATE_TRAP, addr, 0, 0, __KERNEL_CS); } -static inline void set_trap_gate(unsigned int n, void *addr) +static inline void set_system_gate(unsigned int n, void *addr) { BUG_ON((unsigned)n > 0xFF); - _set_gate(n, GATE_TRAP, addr, 0, 0, __KERNEL_CS); +#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 } static inline void set_task_gate(unsigned int n, unsigned int gdt_entry) @@ -375,7 +379,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_intr_gate_ist(int n, void *addr, unsigned ist) +static inline void set_system_gate_ist(int n, void *addr, unsigned ist) { BUG_ON((unsigned)n > 0xFF); _set_gate(n, GATE_INTERRUPT, addr, 0x3, ist, __KERNEL_CS); diff --git a/trunk/include/asm-x86/es7000/mpparse.h b/trunk/include/asm-x86/es7000/mpparse.h index ed5a3caae141..7b5c889d8e7d 100644 --- a/trunk/include/asm-x86/es7000/mpparse.h +++ b/trunk/include/asm-x86/es7000/mpparse.h @@ -5,7 +5,6 @@ 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 diff --git a/trunk/include/asm-x86/fixmap_32.h b/trunk/include/asm-x86/fixmap_32.h index 8844002da0e0..784e3e759866 100644 --- a/trunk/include/asm-x86/fixmap_32.h +++ b/trunk/include/asm-x86/fixmap_32.h @@ -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_SLOTS 4 +#define FIX_BTMAPS_NESTING 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, + FIX_BTMAP_BEGIN = FIX_BTMAP_END + NR_FIX_BTMAPS*FIX_BTMAPS_NESTING - 1, FIX_WP_TEST, #ifdef CONFIG_ACPI FIX_ACPI_BEGIN, diff --git a/trunk/include/asm-x86/fixmap_64.h b/trunk/include/asm-x86/fixmap_64.h index dab4751d1307..dafb24bc0424 100644 --- a/trunk/include/asm-x86/fixmap_64.h +++ b/trunk/include/asm-x86/fixmap_64.h @@ -49,7 +49,6 @@ 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, @@ -57,18 +56,19 @@ 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 256 pages boundary so that we + * We round it up to the next 512 pages boundary so that we * can have a single pgd entry and a single pte table: */ #define NR_FIX_BTMAPS 64 -#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, +#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, __end_of_fixed_addresses }; diff --git a/trunk/include/asm-x86/io.h b/trunk/include/asm-x86/io.h index a233f835e0b5..72b7719523bf 100644 --- a/trunk/include/asm-x86/io.h +++ b/trunk/include/asm-x86/io.h @@ -5,6 +5,20 @@ #include +/* + * 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) \ @@ -83,7 +97,6 @@ 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); diff --git a/trunk/include/asm-x86/io_64.h b/trunk/include/asm-x86/io_64.h index ee6e086b7dfe..64429e9431a8 100644 --- a/trunk/include/asm-x86/io_64.h +++ b/trunk/include/asm-x86/io_64.h @@ -165,6 +165,9 @@ static inline void *phys_to_virt(unsigned long address) #include +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 diff --git a/trunk/include/asm-x86/ioctls.h b/trunk/include/asm-x86/ioctls.h index 06752a649044..336603512399 100644 --- a/trunk/include/asm-x86/ioctls.h +++ b/trunk/include/asm-x86/ioctls.h @@ -51,15 +51,9 @@ #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 diff --git a/trunk/include/asm-x86/irqflags.h b/trunk/include/asm-x86/irqflags.h index 2bdab21f0898..424acb48cd61 100644 --- a/trunk/include/asm-x86/irqflags.h +++ b/trunk/include/asm-x86/irqflags.h @@ -166,6 +166,27 @@ 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 diff --git a/trunk/include/asm-x86/kdebug.h b/trunk/include/asm-x86/kdebug.h index fbbab66ee9df..5ec3ad3e825c 100644 --- a/trunk/include/asm-x86/kdebug.h +++ b/trunk/include/asm-x86/kdebug.h @@ -27,9 +27,10 @@ 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, int all); +extern void __show_regs(struct pt_regs *regs); 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); diff --git a/trunk/include/asm-x86/kprobes.h b/trunk/include/asm-x86/kprobes.h index 8a0748d01036..bd8407863c13 100644 --- a/trunk/include/asm-x86/kprobes.h +++ b/trunk/include/asm-x86/kprobes.h @@ -82,6 +82,15 @@ 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); diff --git a/trunk/include/asm-x86/mach-default/mach_traps.h b/trunk/include/asm-x86/mach-default/mach_traps.h index ff8778f26b84..de9ac3f5c4ce 100644 --- a/trunk/include/asm-x86/mach-default/mach_traps.h +++ b/trunk/include/asm-x86/mach-default/mach_traps.h @@ -7,6 +7,12 @@ #include +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); diff --git a/trunk/include/asm-x86/module.h b/trunk/include/asm-x86/module.h index 864f2005fc1d..48dc3e0c07d9 100644 --- a/trunk/include/asm-x86/module.h +++ b/trunk/include/asm-x86/module.h @@ -52,6 +52,8 @@ 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 diff --git a/trunk/include/asm-x86/nmi.h b/trunk/include/asm-x86/nmi.h index a53f829a97c5..d5e715f024dc 100644 --- a/trunk/include/asm-x86/nmi.h +++ b/trunk/include/asm-x86/nmi.h @@ -15,6 +15,10 @@ */ 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; diff --git a/trunk/include/asm-x86/page.h b/trunk/include/asm-x86/page.h index d4f1d5791fc1..c91574776751 100644 --- a/trunk/include/asm-x86/page.h +++ b/trunk/include/asm-x86/page.h @@ -179,7 +179,6 @@ 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))) @@ -189,14 +188,9 @@ 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) -extern bool __virt_addr_valid(unsigned long kaddr); -#define virt_addr_valid(kaddr) __virt_addr_valid((unsigned long) (kaddr)) +#define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT) #endif /* __ASSEMBLY__ */ diff --git a/trunk/include/asm-x86/page_32.h b/trunk/include/asm-x86/page_32.h index e8d80d1de237..9c5a737a9af9 100644 --- a/trunk/include/asm-x86/page_32.h +++ b/trunk/include/asm-x86/page_32.h @@ -20,12 +20,6 @@ #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 */ @@ -79,11 +73,11 @@ typedef struct page *pgtable_t; #endif #ifndef __ASSEMBLY__ -#define __phys_addr_nodebug(x) ((x) - PAGE_OFFSET) +#define __phys_addr_const(x) ((x) - PAGE_OFFSET) #ifdef CONFIG_DEBUG_VIRTUAL extern unsigned long __phys_addr(unsigned long); #else -#define __phys_addr(x) __phys_addr_nodebug(x) +#define __phys_addr(x) ((x) - PAGE_OFFSET) #endif #define __phys_reloc_hide(x) RELOC_HIDE((x), 0) diff --git a/trunk/include/asm-x86/pgtable.h b/trunk/include/asm-x86/pgtable.h index 182f9d4c570f..ed932453ef26 100644 --- a/trunk/include/asm-x86/pgtable.h +++ b/trunk/include/asm-x86/pgtable.h @@ -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_IOMAP 10 /* flag used to indicate IO mapping */ +#define _PAGE_BIT_UNUSED2 10 #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_IOMAP (_AT(pteval_t, 1) << _PAGE_BIT_IOMAP) +#define _PAGE_UNUSED2 (_AT(pteval_t, 1) << _PAGE_BIT_UNUSED2) #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) @@ -99,11 +99,6 @@ #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) @@ -118,11 +113,6 @@ #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 @@ -206,7 +196,7 @@ static inline int pte_exec(pte_t pte) static inline int pte_special(pte_t pte) { - return pte_flags(pte) & _PAGE_SPECIAL; + return pte_val(pte) & _PAGE_SPECIAL; } static inline unsigned long pte_pfn(pte_t pte) diff --git a/trunk/include/asm-x86/ptrace.h b/trunk/include/asm-x86/ptrace.h index a2025525a15a..ac578f11c1c5 100644 --- a/trunk/include/asm-x86/ptrace.h +++ b/trunk/include/asm-x86/ptrace.h @@ -174,8 +174,12 @@ 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 *); diff --git a/trunk/include/asm-x86/segment.h b/trunk/include/asm-x86/segment.h index 5d6e69454891..ea5f0a8686f7 100644 --- a/trunk/include/asm-x86/segment.h +++ b/trunk/include/asm-x86/segment.h @@ -131,6 +131,12 @@ * 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) diff --git a/trunk/include/asm-x86/smp.h b/trunk/include/asm-x86/smp.h index a6afc29f2dd9..6df2615f9138 100644 --- a/trunk/include/asm-x86/smp.h +++ b/trunk/include/asm-x86/smp.h @@ -141,8 +141,6 @@ 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) @@ -151,11 +149,15 @@ 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 /* CONFIG_SMP */ +#endif extern unsigned disabled_cpus __cpuinitdata; diff --git a/trunk/include/asm-x86/statfs.h b/trunk/include/asm-x86/statfs.h index ca5dc19dd461..3f005bc3aa5b 100644 --- a/trunk/include/asm-x86/statfs.h +++ b/trunk/include/asm-x86/statfs.h @@ -1,12 +1,63 @@ #ifndef ASM_X86__STATFS_H #define ASM_X86__STATFS_H +#ifdef __i386__ +#include +#else + +#ifndef __KERNEL_STRICT_NAMES + +#include + +typedef __kernel_fsid_t fsid_t; + +#endif + /* - * 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. + * This is ugly -- we're already 64-bit clean, so just duplicate the + * definitions. */ -#define ARCH_PACK_COMPAT_STATFS64 __attribute__((packed,aligned(4))) +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]; +}; -#include +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]; +} __attribute__((packed)); + +#endif /* !__i386__ */ #endif /* ASM_X86__STATFS_H */ diff --git a/trunk/include/asm-x86/system.h b/trunk/include/asm-x86/system.h index b20c894660f9..34505dd7b24d 100644 --- a/trunk/include/asm-x86/system.h +++ b/trunk/include/asm-x86/system.h @@ -64,10 +64,7 @@ do { \ \ /* regparm parameters for __switch_to(): */ \ [prev] "a" (prev), \ - [next] "d" (next) \ - \ - : /* reloaded segment registers */ \ - "memory"); \ + [next] "d" (next)); \ } while (0) /* diff --git a/trunk/include/asm-x86/traps.h b/trunk/include/asm-x86/traps.h index 6c3dc2c65751..7a692baa51ae 100644 --- a/trunk/include/asm-x86/traps.h +++ b/trunk/include/asm-x86/traps.h @@ -3,12 +3,7 @@ #include -#ifdef CONFIG_X86_32 -#define dotraplinkage -#else -#define dotraplinkage asmlinkage -#endif - +/* Common in X86_32 and X86_64 */ asmlinkage void divide_error(void); asmlinkage void debug(void); asmlinkage void nmi(void); @@ -17,47 +12,31 @@ 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); -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 +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); static inline int get_si_code(unsigned long condition) { @@ -73,9 +52,31 @@ 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/trunk/include/asm-xtensa/a.out.h b/trunk/include/asm-xtensa/a.out.h new file mode 100644 index 000000000000..fdf13702924a --- /dev/null +++ b/trunk/include/asm-xtensa/a.out.h @@ -0,0 +1,29 @@ +/* + * 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 */ diff --git a/trunk/include/linux/devpts_fs.h b/trunk/include/linux/devpts_fs.h index 5ce0e5fd712e..154769cad3f3 100644 --- a/trunk/include/linux/devpts_fs.h +++ b/trunk/include/linux/devpts_fs.h @@ -17,31 +17,20 @@ #ifdef CONFIG_UNIX98_PTYS -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); +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 */ #else /* Dummy stubs in the no-pty case */ -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) { } +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) { } #endif diff --git a/trunk/include/linux/dmi.h b/trunk/include/linux/dmi.h index e5084eb5943a..2a063b64133f 100644 --- a/trunk/include/linux/dmi.h +++ b/trunk/include/linux/dmi.h @@ -2,9 +2,29 @@ #define __DMI_H__ #include -#include -/* enum dmi_field is in 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_device_type { DMI_DEV_TYPE_ANY = 0, @@ -28,6 +48,23 @@ 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; diff --git a/trunk/include/linux/hpet.h b/trunk/include/linux/hpet.h index 79f63a27bcef..2dc29ce6c8e4 100644 --- a/trunk/include/linux/hpet.h +++ b/trunk/include/linux/hpet.h @@ -37,7 +37,6 @@ struct hpet { #define hpet_compare _u1._hpet_compare #define HPET_MAX_TIMERS (32) -#define HPET_MAX_IRQ (32) /* * HPET general capabilities register @@ -65,7 +64,7 @@ struct hpet { */ #define Tn_INT_ROUTE_CAP_MASK (0xffffffff00000000ULL) -#define Tn_INT_ROUTE_CAP_SHIFT (32UL) +#define Tn_INI_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) @@ -92,14 +91,23 @@ 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); @@ -117,7 +125,7 @@ struct hpet_info { unsigned short hi_timer; }; -#define HPET_INFO_PERIODIC 0x0010 /* periodic-capable comparator */ +#define HPET_INFO_PERIODIC 0x0001 /* timer is periodic */ #define HPET_IE_ON _IO('h', 0x01) /* interrupt on */ #define HPET_IE_OFF _IO('h', 0x02) /* interrupt off */ diff --git a/trunk/include/linux/magic.h b/trunk/include/linux/magic.h index f7f3fdddbef0..1fa0c2ce4dec 100644 --- a/trunk/include/linux/magic.h +++ b/trunk/include/linux/magic.h @@ -6,10 +6,6 @@ #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 diff --git a/trunk/include/linux/mod_devicetable.h b/trunk/include/linux/mod_devicetable.h index 3481a7d5bc0a..c4db5827963d 100644 --- a/trunk/include/linux/mod_devicetable.h +++ b/trunk/include/linux/mod_devicetable.h @@ -388,52 +388,5 @@ 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 */ diff --git a/trunk/include/linux/oprofile.h b/trunk/include/linux/oprofile.h index bcb8f725427c..041bb31100f4 100644 --- a/trunk/include/linux/oprofile.h +++ b/trunk/include/linux/oprofile.h @@ -36,8 +36,6 @@ #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; diff --git a/trunk/include/linux/pci_ids.h b/trunk/include/linux/pci_ids.h index 1176f1f177e2..f63b5455801c 100644 --- a/trunk/include/linux/pci_ids.h +++ b/trunk/include/linux/pci_ids.h @@ -1533,9 +1533,7 @@ #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_88ALP01_NAND 0x4100 -#define PCI_DEVICE_ID_MARVELL_88ALP01_SD 0x4101 -#define PCI_DEVICE_ID_MARVELL_88ALP01_CCIC 0x4102 +#define PCI_DEVICE_ID_MARVELL_CAFE_SD 0x4101 #define PCI_VENDOR_ID_V3 0x11b0 #define PCI_DEVICE_ID_V3_V960 0x0001 diff --git a/trunk/include/linux/serial.h b/trunk/include/linux/serial.h index 1ea8d9265bf6..deb714314fb1 100644 --- a/trunk/include/linux/serial.h +++ b/trunk/include/linux/serial.h @@ -173,22 +173,6 @@ 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 diff --git a/trunk/include/linux/serial_core.h b/trunk/include/linux/serial_core.h index e27f216361fc..3b2f6c04855e 100644 --- a/trunk/include/linux/serial_core.h +++ b/trunk/include/linux/serial_core.h @@ -241,7 +241,7 @@ typedef unsigned int __bitwise__ upf_t; struct uart_port { spinlock_t lock; /* port lock */ - unsigned long iobase; /* in/out[bwl] */ + unsigned int iobase; /* in/out[bwl] */ unsigned char __iomem *membase; /* read/write[bwl] */ unsigned int irq; /* irq number */ unsigned int uartclk; /* base uart clock */ diff --git a/trunk/include/linux/termios.h b/trunk/include/linux/termios.h index 2acd0c1f8a2a..478662889f48 100644 --- a/trunk/include/linux/termios.h +++ b/trunk/include/linux/termios.h @@ -4,19 +4,4 @@ #include #include -#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 diff --git a/trunk/include/linux/tty.h b/trunk/include/linux/tty.h index 3b8121d4e36f..0cbec74ec086 100644 --- a/trunk/include/linux/tty.h +++ b/trunk/include/linux/tty.h @@ -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 19 +#define NR_LDISCS 18 /* line disciplines */ #define N_TTY 0 @@ -45,7 +45,6 @@ #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 @@ -182,7 +181,6 @@ 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 */ @@ -210,7 +208,6 @@ struct tty_operations; struct tty_struct { int magic; - struct kref kref; struct tty_driver *driver; const struct tty_operations *ops; int index; @@ -220,7 +217,6 @@ 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; @@ -314,25 +310,6 @@ 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); @@ -356,15 +333,13 @@ 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); @@ -372,9 +347,6 @@ 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); @@ -400,15 +372,6 @@ 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; @@ -419,8 +382,6 @@ 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); @@ -466,7 +427,7 @@ static inline void tty_audit_push_task(struct task_struct *tsk, #endif /* tty_ioctl.c */ -extern int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file, +extern int n_tty_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg); /* serial.c */ diff --git a/trunk/include/linux/tty_driver.h b/trunk/include/linux/tty_driver.h index 78416b901589..16d27944c321 100644 --- a/trunk/include/linux/tty_driver.h +++ b/trunk/include/linux/tty_driver.h @@ -7,28 +7,6 @@ * 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. @@ -43,11 +21,6 @@ * * 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); * @@ -207,14 +180,6 @@ * 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 @@ -225,13 +190,8 @@ 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); @@ -260,7 +220,6 @@ 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); @@ -270,7 +229,6 @@ 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; @@ -284,6 +242,7 @@ 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 */ @@ -305,19 +264,12 @@ struct tty_driver { extern struct list_head tty_drivers; -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, +struct tty_driver *alloc_tty_driver(int lines); +void put_tty_driver(struct tty_driver *driver); +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 diff --git a/trunk/include/linux/vt_kern.h b/trunk/include/linux/vt_kern.h index 2f1113467f70..1cbd0a7db4e6 100644 --- a/trunk/include/linux/vt_kern.h +++ b/trunk/include/linux/vt_kern.h @@ -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(const struct file_operations *console_fops); +int vty_init(void); /* * vc_screen.c shares this temporary buffer with the console write code so that diff --git a/trunk/include/net/cipso_ipv4.h b/trunk/include/net/cipso_ipv4.h index 9909774eb998..a6bb94530cfd 100644 --- a/trunk/include/net/cipso_ipv4.h +++ b/trunk/include/net/cipso_ipv4.h @@ -40,12 +40,11 @@ #include #include #include -#include /* known doi values */ #define CIPSO_V4_DOI_UNKNOWN 0x00000000 -/* standard tag types */ +/* tag types */ #define CIPSO_V4_TAG_INVALID 0 #define CIPSO_V4_TAG_RBITMAP 1 #define CIPSO_V4_TAG_ENUM 2 @@ -53,14 +52,10 @@ #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_TRANS 1 +#define CIPSO_V4_MAP_STD 1 #define CIPSO_V4_MAP_PASS 2 -#define CIPSO_V4_MAP_LOCAL 3 /* limits */ #define CIPSO_V4_MAX_REM_LVLS 255 @@ -84,9 +79,10 @@ struct cipso_v4_doi { } map; u8 tags[CIPSO_V4_TAG_MAXCNT]; - atomic_t refcount; + u32 valid; struct list_head list; struct rcu_head rcu; + struct list_head dom_list; }; /* Standard CIPSO mapping table */ @@ -132,26 +128,25 @@ extern int cipso_v4_rbm_strictvalid; #ifdef CONFIG_NETLABEL int cipso_v4_doi_add(struct cipso_v4_doi *doi_def); -void cipso_v4_doi_free(struct cipso_v4_doi *doi_def); -int cipso_v4_doi_remove(u32 doi, struct netlbl_audit *audit_info); +int cipso_v4_doi_remove(u32 doi, + struct netlbl_audit *audit_info, + void (*callback) (struct rcu_head * head)); 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) + struct netlbl_audit *audit_info, + void (*callback) (struct rcu_head * head)) { return 0; } @@ -211,15 +206,10 @@ 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(const struct sk_buff *skb, unsigned char **option); +int cipso_v4_validate(unsigned char **option); #else static inline void cipso_v4_error(struct sk_buff *skb, int error, @@ -235,36 +225,19 @@ 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(const struct sk_buff *skb, - unsigned char **option) +static inline int cipso_v4_validate(unsigned char **option) { return -ENOSYS; } diff --git a/trunk/include/net/netlabel.h b/trunk/include/net/netlabel.h index 17c442a4514e..e4d2d6baa983 100644 --- a/trunk/include/net/netlabel.h +++ b/trunk/include/net/netlabel.h @@ -9,7 +9,7 @@ */ /* - * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008 + * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 * * 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,10 +72,8 @@ 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 3 +#define NETLBL_PROTO_VERSION 2 /* NetLabel NETLINK types/families */ #define NETLBL_NLTYPE_NONE 0 @@ -89,8 +87,6 @@ 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. @@ -204,7 +200,7 @@ struct netlbl_lsm_secattr { u32 type; char *domain; struct netlbl_lsm_cache *cache; - struct { + union { struct { struct netlbl_lsm_secattr_catmap *cat; u32 lvl; @@ -356,9 +352,12 @@ 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 @@ -381,19 +380,12 @@ 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, int gateway); +void netlbl_skbuff_err(struct sk_buff *skb, int error); /* * LSM label mapping cache operations @@ -412,12 +404,22 @@ 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) @@ -454,35 +456,18 @@ 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, - int gateway) +static inline void netlbl_skbuff_err(struct sk_buff *skb, int error) { return; } diff --git a/trunk/include/sound/soc-dapm.h b/trunk/include/sound/soc-dapm.h index ca699a3017f3..c1b26fcc0b5c 100644 --- a/trunk/include/sound/soc-dapm.h +++ b/trunk/include/sound/soc-dapm.h @@ -240,7 +240,6 @@ 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); diff --git a/trunk/init/Kconfig b/trunk/init/Kconfig index 8a8e2d00c40e..c11da38837e5 100644 --- a/trunk/init/Kconfig +++ b/trunk/init/Kconfig @@ -779,6 +779,16 @@ 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 diff --git a/trunk/kernel/acct.c b/trunk/kernel/acct.c index f6006a60df5d..dd68b9059418 100644 --- a/trunk/kernel/acct.c +++ b/trunk/kernel/acct.c @@ -548,7 +548,7 @@ static void do_acct_process(struct bsd_acct_struct *acct, #endif spin_lock_irq(¤t->sighand->siglock); - tty = current->signal->tty; /* Safe as we hold the siglock */ + tty = current->signal->tty; 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))); diff --git a/trunk/kernel/auditsc.c b/trunk/kernel/auditsc.c index cf5bc2f5f9c3..59cedfb040e7 100644 --- a/trunk/kernel/auditsc.c +++ b/trunk/kernel/auditsc.c @@ -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; + 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); - spin_lock_irq(&tsk->sighand->siglock); + mutex_lock(&tty_mutex); + read_lock(&tasklist_lock); if (tsk->signal && tsk->signal->tty && tsk->signal->tty->name) tty = tsk->signal->tty->name; else tty = "(none)"; - spin_unlock_irq(&tsk->sighand->siglock); - + read_unlock(&tasklist_lock); 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,6 +1230,7 @@ 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) { diff --git a/trunk/kernel/fork.c b/trunk/kernel/fork.c index 30de644a40c4..7ce2ebe84796 100644 --- a/trunk/kernel/fork.c +++ b/trunk/kernel/fork.c @@ -802,7 +802,6 @@ 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; @@ -839,7 +838,6 @@ 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); } @@ -1229,8 +1227,7 @@ static struct task_struct *copy_process(unsigned long clone_flags, p->nsproxy->pid_ns->child_reaper = p; p->signal->leader_pid = pid; - tty_kref_put(p->signal->tty); - p->signal->tty = tty_kref_get(current->signal->tty); + p->signal->tty = 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)); diff --git a/trunk/kernel/printk.c b/trunk/kernel/printk.c index a430fd04008b..b51b1567bb55 100644 --- a/trunk/kernel/printk.c +++ b/trunk/kernel/printk.c @@ -1291,6 +1291,22 @@ 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 /* diff --git a/trunk/kernel/sched_debug.c b/trunk/kernel/sched_debug.c index ad958c1ec708..bbe6b31c3c56 100644 --- a/trunk/kernel/sched_debug.c +++ b/trunk/kernel/sched_debug.c @@ -333,10 +333,12 @@ 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, diff --git a/trunk/kernel/sys.c b/trunk/kernel/sys.c index 234d9454294e..038a7bc0901d 100644 --- a/trunk/kernel/sys.c +++ b/trunk/kernel/sys.c @@ -1060,7 +1060,9 @@ asmlinkage long sys_setsid(void) group_leader->signal->leader = 1; __set_special_pids(sid); - proc_clear_tty(group_leader); + spin_lock(&group_leader->sighand->siglock); + group_leader->signal->tty = NULL; + spin_unlock(&group_leader->sighand->siglock); err = session; out: diff --git a/trunk/kernel/sysctl.c b/trunk/kernel/sysctl.c index c468c3c6dfc5..1bf369bd4423 100644 --- a/trunk/kernel/sysctl.c +++ b/trunk/kernel/sysctl.c @@ -80,6 +80,7 @@ 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 @@ -806,6 +807,16 @@ 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, diff --git a/trunk/mm/shmem.c b/trunk/mm/shmem.c index bf66d0191baf..04fb4f1ab88e 100644 --- a/trunk/mm/shmem.c +++ b/trunk/mm/shmem.c @@ -50,12 +50,14 @@ #include #include #include -#include #include #include #include +/* 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) diff --git a/trunk/net/ipv4/cipso_ipv4.c b/trunk/net/ipv4/cipso_ipv4.c index 490e035c6d90..2c0e4572cc90 100644 --- a/trunk/net/ipv4/cipso_ipv4.c +++ b/trunk/net/ipv4/cipso_ipv4.c @@ -13,7 +13,7 @@ */ /* - * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008 + * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 * * 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 @@ -47,7 +47,17 @@ #include #include +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 @@ -109,19 +119,6 @@ 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 */ @@ -196,6 +193,25 @@ 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 @@ -441,7 +457,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 && atomic_read(&iter->refcount)) + if (iter->doi == doi && iter->valid) return iter; return NULL; } @@ -480,17 +496,14 @@ 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; } } - atomic_set(&doi_def->refcount, 1); + doi_def->valid = 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) @@ -505,130 +518,60 @@ int cipso_v4_doi_add(struct cipso_v4_doi *doi_def) 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. 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, @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. * */ -int cipso_v4_doi_remove(u32 doi, struct netlbl_audit *audit_info) +int cipso_v4_doi_remove(u32 doi, + struct netlbl_audit *audit_info, + void (*callback) (struct rcu_head * head)) { 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) { + if (doi_def != NULL) { + doi_def->valid = 0; + list_del_rcu(&doi_def->list); spin_unlock(&cipso_v4_doi_list_lock); - return -ENOENT; - } - if (!atomic_dec_and_test(&doi_def->refcount)) { - spin_unlock(&cipso_v4_doi_list_lock); - return -EBUSY; + 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; } - 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); - - return 0; + return -ENOENT; } /** - * cipso_v4_doi_getdef - Returns a reference to a valid DOI definition + * cipso_v4_doi_getdef - Returns a pointer 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 and the DOI - * definition reference count is decremented when the caller is done. + * rcu_read_lock() is held while accessing the returned definition. * */ struct cipso_v4_doi *cipso_v4_doi_getdef(u32 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); + return cipso_v4_doi_search(doi); } /** @@ -654,7 +597,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 (atomic_read(&iter_doi->refcount) > 0) { + if (iter_doi->valid) { if (doi_cnt++ < *skip_cnt) continue; ret_val = callback(iter_doi, cb_arg); @@ -670,6 +613,85 @@ int cipso_v4_doi_walk(u32 *skip_cnt, 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 */ @@ -690,7 +712,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_TRANS: + case CIPSO_V4_MAP_STD: if (doi_def->map.std->lvl.cipso[level] < CIPSO_V4_INV_LVL) return 0; break; @@ -719,7 +741,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_TRANS: + case CIPSO_V4_MAP_STD: 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]; @@ -753,7 +775,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_TRANS: + case CIPSO_V4_MAP_STD: map_tbl = doi_def->map.std; if (net_lvl < map_tbl->lvl.cipso_size && map_tbl->lvl.cipso[net_lvl] < CIPSO_V4_INV_LVL) { @@ -790,7 +812,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_TRANS: + case CIPSO_V4_MAP_STD: cipso_cat_size = doi_def->map.std->cat.cipso_size; cipso_array = doi_def->map.std->cat.cipso; for (;;) { @@ -838,7 +860,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_TRANS) { + if (doi_def->type == CIPSO_V4_MAP_STD) { host_cat_size = doi_def->map.std->cat.local_size; host_cat_array = doi_def->map.std->cat.local; } @@ -853,7 +875,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_TRANS: + case CIPSO_V4_MAP_STD: if (host_spot >= host_cat_size) return -EPERM; net_spot = host_cat_array[host_spot]; @@ -899,7 +921,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_TRANS) { + if (doi_def->type == CIPSO_V4_MAP_STD) { net_cat_size = doi_def->map.std->cat.cipso_size; net_cat_array = doi_def->map.std->cat.cipso; } @@ -919,7 +941,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_TRANS: + case CIPSO_V4_MAP_STD: if (net_spot >= net_cat_size) return -EPERM; host_spot = net_cat_array[net_spot]; @@ -1255,7 +1277,7 @@ static int cipso_v4_gentag_rbm(const struct cipso_v4_doi *doi_def, } else tag_len = 4; - buffer[0] = CIPSO_V4_TAG_RBITMAP; + buffer[0] = 0x01; buffer[1] = tag_len; buffer[3] = level; @@ -1351,7 +1373,7 @@ static int cipso_v4_gentag_enum(const struct cipso_v4_doi *doi_def, } else tag_len = 4; - buffer[0] = CIPSO_V4_TAG_ENUM; + buffer[0] = 0x02; buffer[1] = tag_len; buffer[3] = level; @@ -1447,7 +1469,7 @@ static int cipso_v4_gentag_rng(const struct cipso_v4_doi *doi_def, } else tag_len = 4; - buffer[0] = CIPSO_V4_TAG_RANGE; + buffer[0] = 0x05; buffer[1] = tag_len; buffer[3] = level; @@ -1500,54 +1522,6 @@ 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 @@ -1567,7 +1541,7 @@ static int cipso_v4_parsetag_loc(const struct cipso_v4_doi *doi_def, * that is unrecognized." * */ -int cipso_v4_validate(const struct sk_buff *skb, unsigned char **option) +int cipso_v4_validate(unsigned char **option) { unsigned char *opt = *option; unsigned char *tag; @@ -1592,7 +1566,7 @@ int cipso_v4_validate(const struct sk_buff *skb, unsigned char **option) goto validate_return_locked; } - opt_iter = CIPSO_V4_HDR_LEN; + opt_iter = 6; tag = opt + opt_iter; while (opt_iter < opt_len) { for (tag_iter = 0; doi_def->tags[tag_iter] != tag[0];) @@ -1610,7 +1584,7 @@ int cipso_v4_validate(const struct sk_buff *skb, unsigned char **option) switch (tag[0]) { case CIPSO_V4_TAG_RBITMAP: - if (tag_len < CIPSO_V4_TAG_RBM_BLEN) { + if (tag_len < 4) { err_offset = opt_iter + 1; goto validate_return_locked; } @@ -1628,7 +1602,7 @@ int cipso_v4_validate(const struct sk_buff *skb, unsigned char **option) err_offset = opt_iter + 3; goto validate_return_locked; } - if (tag_len > CIPSO_V4_TAG_RBM_BLEN && + if (tag_len > 4 && cipso_v4_map_cat_rbm_valid(doi_def, &tag[4], tag_len - 4) < 0) { @@ -1638,7 +1612,7 @@ int cipso_v4_validate(const struct sk_buff *skb, unsigned char **option) } break; case CIPSO_V4_TAG_ENUM: - if (tag_len < CIPSO_V4_TAG_ENUM_BLEN) { + if (tag_len < 4) { err_offset = opt_iter + 1; goto validate_return_locked; } @@ -1648,7 +1622,7 @@ int cipso_v4_validate(const struct sk_buff *skb, unsigned char **option) err_offset = opt_iter + 3; goto validate_return_locked; } - if (tag_len > CIPSO_V4_TAG_ENUM_BLEN && + if (tag_len > 4 && cipso_v4_map_cat_enum_valid(doi_def, &tag[4], tag_len - 4) < 0) { @@ -1657,7 +1631,7 @@ int cipso_v4_validate(const struct sk_buff *skb, unsigned char **option) } break; case CIPSO_V4_TAG_RANGE: - if (tag_len < CIPSO_V4_TAG_RNG_BLEN) { + if (tag_len < 4) { err_offset = opt_iter + 1; goto validate_return_locked; } @@ -1667,7 +1641,7 @@ int cipso_v4_validate(const struct sk_buff *skb, unsigned char **option) err_offset = opt_iter + 3; goto validate_return_locked; } - if (tag_len > CIPSO_V4_TAG_RNG_BLEN && + if (tag_len > 4 && cipso_v4_map_cat_rng_valid(doi_def, &tag[4], tag_len - 4) < 0) { @@ -1675,19 +1649,6 @@ int cipso_v4_validate(const struct sk_buff *skb, 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; @@ -1743,27 +1704,48 @@ void cipso_v4_error(struct sk_buff *skb, int error, u32 gateway) } /** - * cipso_v4_genopt - Generate a CIPSO option - * @buf: the option buffer - * @buf_len: the size of opt_buf + * cipso_v4_sock_setattr - Add a CIPSO option to a socket + * @sk: the socket * @doi_def: the CIPSO DOI to use - * @secattr: the security attributes + * @secattr: the specific security attributes of the socket * * Description: - * 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. + * 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. * */ -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 cipso_v4_sock_setattr(struct sock *sk, + const struct cipso_v4_doi *doi_def, + const struct netlbl_lsm_secattr *secattr) { - int ret_val; + int ret_val = -EPERM; 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; - if (buf_len <= CIPSO_V4_HDR_LEN) - return -ENOSPC; + /* 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; + } /* 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 @@ -1790,73 +1772,19 @@ static int cipso_v4_genopt(unsigned char *buf, u32 buf_len, &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: - return -EPERM; + ret_val = -EPERM; + goto socket_setattr_failure; } iter++; } while (ret_val < 0 && iter < CIPSO_V4_TAG_MAXCNT && doi_def->tags[iter] != CIPSO_V4_TAG_INVALID); - if (ret_val < 0) - return ret_val; - cipso_v4_gentag_hdr(doi_def, buf, 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; + cipso_v4_gentag_hdr(doi_def, buf, ret_val); + buf_len = CIPSO_V4_HDR_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 @@ -1893,80 +1821,6 @@ int cipso_v4_sock_setattr(struct sock *sk, 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 @@ -2005,9 +1859,6 @@ 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; @@ -2041,123 +1892,6 @@ 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 diff --git a/trunk/net/ipv4/ip_options.c b/trunk/net/ipv4/ip_options.c index 2c88da6e7862..be3f18a7a40e 100644 --- a/trunk/net/ipv4/ip_options.c +++ b/trunk/net/ipv4/ip_options.c @@ -438,7 +438,7 @@ int ip_options_compile(struct net *net, goto error; } opt->cipso = optptr - iph; - if (cipso_v4_validate(skb, &optptr)) { + if (cipso_v4_validate(&optptr)) { pp_ptr = optptr; goto error; } diff --git a/trunk/net/netlabel/Makefile b/trunk/net/netlabel/Makefile index ea750e9df65f..8af18c0a47d9 100644 --- a/trunk/net/netlabel/Makefile +++ b/trunk/net/netlabel/Makefile @@ -5,8 +5,7 @@ # # base objects -obj-y := netlabel_user.o netlabel_kapi.o -obj-y += netlabel_domainhash.o netlabel_addrlist.o +obj-y := netlabel_user.o netlabel_kapi.o netlabel_domainhash.o # management objects obj-y += netlabel_mgmt.o diff --git a/trunk/net/netlabel/netlabel_addrlist.c b/trunk/net/netlabel/netlabel_addrlist.c deleted file mode 100644 index b0925a303353..000000000000 --- a/trunk/net/netlabel/netlabel_addrlist.c +++ /dev/null @@ -1,388 +0,0 @@ -/* - * 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 - * - */ - -/* - * (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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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/trunk/net/netlabel/netlabel_addrlist.h b/trunk/net/netlabel/netlabel_addrlist.h deleted file mode 100644 index 0242bead405f..000000000000 --- a/trunk/net/netlabel/netlabel_addrlist.h +++ /dev/null @@ -1,189 +0,0 @@ -/* - * 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 - * - */ - -/* - * (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 -#include -#include -#include -#include - -/** - * 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 diff --git a/trunk/net/netlabel/netlabel_cipso_v4.c b/trunk/net/netlabel/netlabel_cipso_v4.c index fff32b70efa9..0aec318bf0ef 100644 --- a/trunk/net/netlabel/netlabel_cipso_v4.c +++ b/trunk/net/netlabel/netlabel_cipso_v4.c @@ -43,7 +43,6 @@ #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 { @@ -52,12 +51,6 @@ 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, @@ -87,6 +80,32 @@ 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 @@ -132,9 +151,9 @@ static int netlbl_cipsov4_add_common(struct genl_info *info, * @info: the Generic NETLINK info block * * Description: - * 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. + * 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. * */ static int netlbl_cipsov4_add_std(struct genl_info *info) @@ -164,7 +183,7 @@ static int netlbl_cipsov4_add_std(struct genl_info *info) ret_val = -ENOMEM; goto add_std_failure; } - doi_def->type = CIPSO_V4_MAP_TRANS; + doi_def->type = CIPSO_V4_MAP_STD; ret_val = netlbl_cipsov4_add_common(info, doi_def); if (ret_val != 0) @@ -323,7 +342,7 @@ static int netlbl_cipsov4_add_std(struct genl_info *info) add_std_failure: if (doi_def) - cipso_v4_doi_free(doi_def); + netlbl_cipsov4_doi_free(&doi_def->rcu); return ret_val; } @@ -360,44 +379,7 @@ static int netlbl_cipsov4_add_pass(struct genl_info *info) return 0; add_pass_failure: - 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); + netlbl_cipsov4_doi_free(&doi_def->rcu); return ret_val; } @@ -430,18 +412,14 @@ 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_TRANS: - type_str = "trans"; + case CIPSO_V4_MAP_STD: + type_str = "std"; 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); @@ -513,7 +491,7 @@ static int netlbl_cipsov4_list(struct sk_buff *skb, struct genl_info *info) doi_def = cipso_v4_doi_getdef(doi); if (doi_def == NULL) { ret_val = -EINVAL; - goto list_failure_lock; + goto list_failure; } ret_val = nla_put_u32(ans_skb, NLBL_CIPSOV4_A_MTYPE, doi_def->type); @@ -538,7 +516,7 @@ static int netlbl_cipsov4_list(struct sk_buff *skb, struct genl_info *info) nla_nest_end(ans_skb, nla_a); switch (doi_def->type) { - case CIPSO_V4_MAP_TRANS: + case CIPSO_V4_MAP_STD: nla_a = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_MLSLVLLST); if (nla_a == NULL) { ret_val = -ENOMEM; @@ -677,7 +655,7 @@ static int netlbl_cipsov4_listall(struct sk_buff *skb, struct netlink_callback *cb) { struct netlbl_cipsov4_doiwalk_arg cb_arg; - u32 doi_skip = cb->args[0]; + int doi_skip = cb->args[0]; cb_arg.nl_cb = cb; cb_arg.skb = skb; @@ -689,29 +667,6 @@ 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 @@ -726,11 +681,8 @@ 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; @@ -738,15 +690,11 @@ 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); - 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); - } + ret_val = cipso_v4_doi_remove(doi, + &audit_info, + netlbl_cipsov4_doi_free); + if (ret_val == 0) + atomic_dec(&netlabel_mgmt_protocount); audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_DEL, &audit_info); diff --git a/trunk/net/netlabel/netlabel_cipso_v4.h b/trunk/net/netlabel/netlabel_cipso_v4.h index c8a4079261f0..220cb9d06b49 100644 --- a/trunk/net/netlabel/netlabel_cipso_v4.h +++ b/trunk/net/netlabel/netlabel_cipso_v4.h @@ -45,13 +45,12 @@ * NLBL_CIPSOV4_A_MTYPE * NLBL_CIPSOV4_A_TAGLST * - * If using CIPSO_V4_MAP_TRANS the following attributes are required: + * If using CIPSO_V4_MAP_STD the following attributes are required: * * NLBL_CIPSOV4_A_MLSLVLLST * NLBL_CIPSOV4_A_MLSCATLST * - * If using CIPSO_V4_MAP_PASS or CIPSO_V4_MAP_LOCAL no additional attributes - * are required. + * If using CIPSO_V4_MAP_PASS no additional attributes are required. * * o REMOVE: * Sent by an application to remove a specific DOI mapping table from the @@ -77,13 +76,12 @@ * NLBL_CIPSOV4_A_MTYPE * NLBL_CIPSOV4_A_TAGLST * - * If using CIPSO_V4_MAP_TRANS the following attributes are required: + * If using CIPSO_V4_MAP_STD the following attributes are required: * * NLBL_CIPSOV4_A_MLSLVLLST * NLBL_CIPSOV4_A_MLSCATLST * - * If using CIPSO_V4_MAP_PASS or CIPSO_V4_MAP_LOCAL no additional attributes - * are required. + * If using CIPSO_V4_MAP_PASS no additional attributes are required. * * o LISTALL: * This message is sent by an application to list the valid DOIs on the diff --git a/trunk/net/netlabel/netlabel_domainhash.c b/trunk/net/netlabel/netlabel_domainhash.c index 5fadf10e5ddf..643c032a3a57 100644 --- a/trunk/net/netlabel/netlabel_domainhash.c +++ b/trunk/net/netlabel/netlabel_domainhash.c @@ -11,7 +11,7 @@ */ /* - * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008 + * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 * * 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,7 +40,6 @@ #include #include "netlabel_mgmt.h" -#include "netlabel_addrlist.h" #include "netlabel_domainhash.h" #include "netlabel_user.h" @@ -73,28 +72,8 @@ 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); } @@ -136,13 +115,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); - bkt_list = &rcu_dereference(netlbl_domhsh)->tbl[bkt]; - list_for_each_entry_rcu(iter, bkt_list, list) + list_for_each_entry_rcu(iter, + &rcu_dereference(netlbl_domhsh)->tbl[bkt], + list) if (iter->valid && strcmp(iter->domain, domain) == 0) return iter; } @@ -177,69 +156,6 @@ 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 */ @@ -297,106 +213,74 @@ int __init netlbl_domhsh_init(u32 size) int netlbl_domhsh_add(struct netlbl_dom_map *entry, struct netlbl_audit *audit_info) { - 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 */ + int ret_val; + u32 bkt; + struct audit_buffer *audit_buf; - rcu_read_lock(); + 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; - spin_lock(&netlbl_domhsh_lock); - 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); + entry->valid = 1; + INIT_RCU_HEAD(&entry->rcu); - if (entry->domain != NULL) { - u32 bkt = netlbl_domhsh_hash(entry->domain); + 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) list_add_tail_rcu(&entry->list, &rcu_dereference(netlbl_domhsh)->tbl[bkt]); - } else { - INIT_LIST_HEAD(&entry->list); + else + ret_val = -EEXIST; + } else { + INIT_LIST_HEAD(&entry->list); + if (rcu_dereference(netlbl_domhsh_def) == NULL) 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 (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; + 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; } -#endif /* IPv6 */ - } else - ret_val = -EINVAL; + } -add_return: - spin_unlock(&netlbl_domhsh_lock); - rcu_read_unlock(); return ret_val; } @@ -418,26 +302,35 @@ int netlbl_domhsh_add_default(struct netlbl_dom_map *entry, } /** - * netlbl_domhsh_remove_entry - Removes a given entry from the domain table - * @entry: the entry to remove + * 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). Caller is responsible for - * ensuring that the RCU read lock is held. Returns zero on success, negative - * on failure. + * lower level protocol handler (i.e. CIPSO). Returns zero on success, + * negative on failure. * */ -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 ret_val = 0; + int ret_val = -ENOENT; + struct netlbl_dom_map *entry; 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) - return -ENOENT; - + goto remove_return; + switch (entry->type) { + case NETLBL_NLTYPE_CIPSOV4: + cipso_v4_doi_domhsh_remove(entry->type_def.cipsov4, + entry->domain); + break; + } spin_lock(&netlbl_domhsh_lock); if (entry->valid) { entry->valid = 0; @@ -445,8 +338,8 @@ int netlbl_domhsh_remove_entry(struct netlbl_dom_map *entry, list_del_rcu(&entry->list); else rcu_assign_pointer(netlbl_domhsh_def, NULL); - } else - ret_val = -ENOENT; + ret_val = 0; + } spin_unlock(&netlbl_domhsh_lock); audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_DEL, audit_info); @@ -458,54 +351,10 @@ int netlbl_domhsh_remove_entry(struct netlbl_dom_map *entry, audit_log_end(audit_buf); } - 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); +remove_return: rcu_read_unlock(); - + if (ret_val == 0) + call_rcu(&entry->rcu, netlbl_domhsh_free_entry); return ret_val; } @@ -539,70 +388,6 @@ 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 @@ -625,7 +410,6 @@ 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; @@ -633,8 +417,9 @@ int netlbl_domhsh_walk(u32 *skip_bkt, for (iter_bkt = *skip_bkt; iter_bkt < rcu_dereference(netlbl_domhsh)->size; iter_bkt++, chain_cnt = 0) { - iter_list = &rcu_dereference(netlbl_domhsh)->tbl[iter_bkt]; - list_for_each_entry_rcu(iter_entry, iter_list, list) + list_for_each_entry_rcu(iter_entry, + &rcu_dereference(netlbl_domhsh)->tbl[iter_bkt], + list) if (iter_entry->valid) { if (chain_cnt++ < *skip_chain) continue; diff --git a/trunk/net/netlabel/netlabel_domainhash.h b/trunk/net/netlabel/netlabel_domainhash.h index bfcb6763a1a1..8220990ceb96 100644 --- a/trunk/net/netlabel/netlabel_domainhash.h +++ b/trunk/net/netlabel/netlabel_domainhash.h @@ -11,7 +11,7 @@ */ /* - * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008 + * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 * * 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 @@ -36,43 +36,16 @@ #include #include -#include "netlabel_addrlist.h" - /* Domain hash table size */ /* XXX - currently this number is an uneducated guess */ #define NETLBL_DOMHSH_BITSIZE 7 -/* 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; -}; +/* Domain mapping definition struct */ struct netlbl_dom_map { char *domain; u32 type; union { struct cipso_v4_doi *cipsov4; - struct netlbl_domaddr_map *addrsel; } type_def; u32 valid; @@ -88,21 +61,12 @@ 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 diff --git a/trunk/net/netlabel/netlabel_kapi.c b/trunk/net/netlabel/netlabel_kapi.c index b32eceb3ab0d..39793a1a93aa 100644 --- a/trunk/net/netlabel/netlabel_kapi.c +++ b/trunk/net/netlabel/netlabel_kapi.c @@ -10,7 +10,7 @@ */ /* - * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008 + * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 * * 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) - return -ENOMEM; + goto cfg_unlbl_add_map_failure; if (domain != NULL) { entry->domain = kstrdup(domain, GFP_ATOMIC); if (entry->domain == NULL) @@ -103,6 +103,49 @@ int netlbl_cfg_unlbl_add_map(const char *domain, 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 @@ -121,71 +164,58 @@ 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) - return -ENOMEM; + goto cfg_cipsov4_add_map_failure; 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; - ret_val = cipso_v4_doi_add(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); if (ret_val != 0) - 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; - } + goto cfg_cipsov4_add_map_failure_unlock; ret_val = netlbl_domhsh_add(entry, audit_info); if (ret_val != 0) - goto cfg_cipsov4_add_map_failure_release_doi; - -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); - } + goto cfg_cipsov4_add_map_failure_remove_doi; + rcu_read_unlock(); - return ret_val; + return 0; -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, audit_info); + cipso_v4_doi_remove(doi_def->doi, audit_info, netlbl_cipsov4_doi_free); +cfg_cipsov4_add_map_failure_unlock: + rcu_read_unlock(); cfg_cipsov4_add_map_failure: if (entry != NULL) kfree(entry->domain); kfree(entry); - goto cfg_cipsov4_add_map_return; + 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); } /* @@ -422,9 +452,7 @@ 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, -EDESTADDRREQ if the domain is configured to use - * network address selectors (can't blindly label the socket), and negative - * values on all other failures. + * Returns zero on success, negative values on failure. * */ int netlbl_sock_setattr(struct sock *sk, @@ -438,9 +466,6 @@ 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, @@ -458,20 +483,6 @@ int netlbl_sock_setattr(struct sock *sk, 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 @@ -489,128 +500,6 @@ 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 @@ -639,7 +528,6 @@ 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 @@ -647,10 +535,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, int gateway) +void netlbl_skbuff_err(struct sk_buff *skb, int error) { if (CIPSO_V4_OPTEXIST(skb)) - cipso_v4_error(skb, error, gateway); + cipso_v4_error(skb, error, 0); } /** diff --git a/trunk/net/netlabel/netlabel_mgmt.c b/trunk/net/netlabel/netlabel_mgmt.c index ee769ecaa13c..44be5d5261f4 100644 --- a/trunk/net/netlabel/netlabel_mgmt.c +++ b/trunk/net/netlabel/netlabel_mgmt.c @@ -10,7 +10,7 @@ */ /* - * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008 + * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 * * 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 @@ -32,13 +32,9 @@ #include #include #include -#include -#include #include #include #include -#include -#include #include #include #include @@ -75,336 +71,85 @@ static const struct nla_policy netlbl_mgmt_genl_policy[NLBL_MGMT_A_MAX + 1] = { }; /* - * Helper Functions + * NetLabel Command Handlers */ /** * netlbl_mgmt_add - Handle an ADD message + * @skb: the NETLINK buffer * @info: the Generic NETLINK info block - * @audit_info: NetLabel audit information * * Description: - * 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. + * 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_common(struct genl_info *info, - struct netlbl_audit *audit_info) +static int netlbl_mgmt_add(struct sk_buff *skb, struct genl_info *info) { int ret_val = -EINVAL; struct netlbl_dom_map *entry = NULL; - struct netlbl_domaddr_map *addrmap = NULL; - struct cipso_v4_doi *cipsov4 = NULL; + size_t tmp_size; 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; } - entry->type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]); - 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); + 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; } - - /* 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 */ + entry->type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]); + nla_strlcpy(entry->domain, info->attrs[NLBL_MGMT_A_DOMAIN], tmp_size); 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]); - cipsov4 = cipso_v4_doi_getdef(tmp_val); - if (cipsov4 == NULL) + /* 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 add_failure; - entry->type_def.cipsov4 = cipsov4; + } + ret_val = netlbl_domhsh_add(entry, &audit_info); + rcu_read_unlock(); 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 @@ -453,9 +198,23 @@ static int netlbl_mgmt_listall_cb(struct netlbl_dom_map *entry, void *arg) if (data == NULL) goto listall_cb_failure; - ret_val = netlbl_mgmt_listentry(cb_arg->skb, entry); + ret_val = nla_put_string(cb_arg->skb, + NLBL_MGMT_A_DOMAIN, + entry->domain); 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); @@ -509,22 +268,56 @@ 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]) || - (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; + if (!info->attrs[NLBL_MGMT_A_PROTOCOL]) + goto adddef_failure; netlbl_netlink_auditinfo(skb, &audit_info); - return netlbl_mgmt_add_common(info, &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; } /** @@ -578,10 +371,19 @@ static int netlbl_mgmt_listdef(struct sk_buff *skb, struct genl_info *info) ret_val = -ENOENT; goto listdef_failure_lock; } - ret_val = netlbl_mgmt_listentry(ans_skb, entry); - rcu_read_unlock(); + ret_val = nla_put_u32(ans_skb, NLBL_MGMT_A_PROTOCOL, entry->type); if (ret_val != 0) - goto listdef_failure; + 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; + } + rcu_read_unlock(); genlmsg_end(ans_skb, data); return genlmsg_reply(ans_skb, info); diff --git a/trunk/net/netlabel/netlabel_mgmt.h b/trunk/net/netlabel/netlabel_mgmt.h index 05d96431f819..a43bff169d6b 100644 --- a/trunk/net/netlabel/netlabel_mgmt.h +++ b/trunk/net/netlabel/netlabel_mgmt.h @@ -45,16 +45,6 @@ * 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 @@ -78,24 +68,13 @@ * Required attributes: * * NLBL_MGMT_A_DOMAIN - * - * If the IP address selectors are not used the following attribute is - * required: - * * NLBL_MGMT_A_PROTOCOL * - * 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: + * If using NETLBL_NLTYPE_CIPSOV4 the following attributes are required: * * NLBL_MGMT_A_CV4DOI * - * If the mapping is using the NETLBL_NLTYPE_UNLABELED type no other - * attributes are required. + * If using NETLBL_NLTYPE_UNLABELED no other attributes are required. * * o ADDDEF: * Sent by an application to set the default domain mapping for the NetLabel @@ -121,23 +100,15 @@ * application there is no payload. On success the kernel should send a * response using the following format. * - * If the IP address selectors are not used the following attribute is - * required: + * Required attributes: * * NLBL_MGMT_A_PROTOCOL * - * 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: + * If using NETLBL_NLTYPE_CIPSOV4 the following attributes are required: * * NLBL_MGMT_A_CV4DOI * - * If the mapping is using the NETLBL_NLTYPE_UNLABELED type no other - * attributes are required. + * If using NETLBL_NLTYPE_UNLABELED no other attributes are required. * * o PROTOCOLS: * Sent by an application to request a list of configured NetLabel protocols @@ -191,26 +162,6 @@ 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) diff --git a/trunk/net/netlabel/netlabel_unlabeled.c b/trunk/net/netlabel/netlabel_unlabeled.c index e8a5c32b0f10..921c118ead89 100644 --- a/trunk/net/netlabel/netlabel_unlabeled.c +++ b/trunk/net/netlabel/netlabel_unlabeled.c @@ -10,7 +10,7 @@ */ /* - * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 - 2008 + * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 - 2007 * * 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,7 +54,6 @@ #include #include "netlabel_user.h" -#include "netlabel_addrlist.h" #include "netlabel_domainhash.h" #include "netlabel_unlabeled.h" #include "netlabel_mgmt.h" @@ -77,20 +76,22 @@ 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; - struct netlbl_af4list list; + u32 valid; + struct list_head 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; - struct netlbl_af6list list; + u32 valid; + struct list_head list; struct rcu_head rcu; }; struct netlbl_unlhsh_iface { @@ -145,6 +146,76 @@ 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 */ @@ -203,28 +274,26 @@ 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_af4list *iter4; - struct netlbl_af4list *tmp4; -#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) - struct netlbl_af6list *iter6; - struct netlbl_af6list *tmp6; -#endif /* IPv6 */ + struct netlbl_unlhsh_addr4 *iter4; + struct netlbl_unlhsh_addr4 *tmp4; + struct netlbl_unlhsh_addr6 *iter6; + struct netlbl_unlhsh_addr6 *tmp6; 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 */ - 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 */ + 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); + } kfree(iface); } @@ -246,6 +315,59 @@ 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 @@ -259,12 +381,12 @@ static u32 netlbl_unlhsh_hash(int ifindex) 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); - bkt_list = &rcu_dereference(netlbl_unlhsh)->tbl[bkt]; - list_for_each_entry_rcu(iter, bkt_list, list) + list_for_each_entry_rcu(iter, + &rcu_dereference(netlbl_unlhsh)->tbl[bkt], + list) if (iter->valid && iter->ifindex == ifindex) return iter; @@ -317,26 +439,43 @@ 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->list.addr = addr->s_addr & mask->s_addr; - entry->list.mask = mask->s_addr; - entry->list.valid = 1; - INIT_RCU_HEAD(&entry->rcu); + entry->addr = addr->s_addr & mask->s_addr; + entry->mask = mask->s_addr; entry->secid = secid; + entry->valid = 1; + INIT_RCU_HEAD(&entry->rcu); spin_lock(&netlbl_unlhsh_lock); - ret_val = netlbl_af4list_add(&entry->list, &iface->addr4_list); - spin_unlock(&netlbl_unlhsh_lock); - - if (ret_val != 0) + 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 ret_val; + 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); + spin_unlock(&netlbl_unlhsh_lock); + return 0; } #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) @@ -359,29 +498,47 @@ 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->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); + 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; + INIT_RCU_HEAD(&entry->rcu); spin_lock(&netlbl_unlhsh_lock); - ret_val = netlbl_af6list_add(&entry->list, &iface->addr6_list); - spin_unlock(&netlbl_unlhsh_lock); - - if (ret_val != 0) + 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); + spin_unlock(&netlbl_unlhsh_lock); return 0; } #endif /* IPv6 */ @@ -501,10 +658,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_af4list_audit_addr(audit_buf, 1, - dev_name, - addr4->s_addr, - mask4->s_addr); + netlbl_unlabel_audit_addr4(audit_buf, + dev_name, + addr4->s_addr, + mask4->s_addr); break; } #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) @@ -515,9 +672,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_af6list_audit_addr(audit_buf, 1, - dev_name, - addr6, mask6); + netlbl_unlabel_audit_addr6(audit_buf, + dev_name, + addr6, mask6); break; } #endif /* IPv6 */ @@ -562,34 +719,35 @@ static int netlbl_unlhsh_remove_addr4(struct net *net, const struct in_addr *mask, struct netlbl_audit *audit_info) { - int ret_val = 0; - struct netlbl_af4list *list_entry; + int ret_val = -ENOENT; struct netlbl_unlhsh_addr4 *entry; - struct audit_buffer *audit_buf; + struct audit_buffer *audit_buf = NULL; struct net_device *dev; - char *secctx; + char *secctx = NULL; u32 secctx_len; spin_lock(&netlbl_unlhsh_lock); - list_entry = netlbl_af4list_remove(addr->s_addr, mask->s_addr, - &iface->addr4_list); + 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; + } 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_af4list_audit_addr(audit_buf, 1, - (dev != NULL ? dev->name : NULL), - addr->s_addr, mask->s_addr); + netlbl_unlabel_audit_addr4(audit_buf, + (dev != NULL ? dev->name : NULL), + entry->addr, entry->mask); if (dev != NULL) dev_put(dev); - if (entry && security_secid_to_secctx(entry->secid, - &secctx, - &secctx_len) == 0) { + if (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); } @@ -623,33 +781,36 @@ static int netlbl_unlhsh_remove_addr6(struct net *net, const struct in6_addr *mask, struct netlbl_audit *audit_info) { - int ret_val = 0; - struct netlbl_af6list *list_entry; + int ret_val = -ENOENT; struct netlbl_unlhsh_addr6 *entry; - struct audit_buffer *audit_buf; + struct audit_buffer *audit_buf = NULL; struct net_device *dev; - char *secctx; + char *secctx = NULL; u32 secctx_len; spin_lock(&netlbl_unlhsh_lock); - list_entry = netlbl_af6list_remove(addr, mask, &iface->addr6_list); + 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; + } 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_af6list_audit_addr(audit_buf, 1, - (dev != NULL ? dev->name : NULL), - addr, mask); + netlbl_unlabel_audit_addr6(audit_buf, + (dev != NULL ? dev->name : NULL), + addr, mask); if (dev != NULL) dev_put(dev); - if (entry && security_secid_to_secctx(entry->secid, - &secctx, - &secctx_len) == 0) { + if (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); } @@ -675,18 +836,16 @@ static int netlbl_unlhsh_remove_addr6(struct net *net, */ static void netlbl_unlhsh_condremove_iface(struct netlbl_unlhsh_iface *iface) { - struct netlbl_af4list *iter4; -#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) - struct netlbl_af6list *iter6; -#endif /* IPv6 */ + struct netlbl_unlhsh_addr4 *iter4; + struct netlbl_unlhsh_addr6 *iter6; spin_lock(&netlbl_unlhsh_lock); - 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 */ + 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; iface->valid = 0; if (iface->ifindex > 0) list_del_rcu(&iface->list); @@ -1190,7 +1349,7 @@ static int netlbl_unlabel_staticlist_gen(u32 cmd, if (addr4) { struct in_addr addr_struct; - addr_struct.s_addr = addr4->list.addr; + addr_struct.s_addr = addr4->addr; ret_val = nla_put(cb_arg->skb, NLBL_UNLABEL_A_IPV4ADDR, sizeof(struct in_addr), @@ -1198,7 +1357,7 @@ static int netlbl_unlabel_staticlist_gen(u32 cmd, if (ret_val != 0) goto list_cb_failure; - addr_struct.s_addr = addr4->list.mask; + addr_struct.s_addr = addr4->mask; ret_val = nla_put(cb_arg->skb, NLBL_UNLABEL_A_IPV4MASK, sizeof(struct in_addr), @@ -1211,14 +1370,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->list.addr); + &addr6->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->list.mask); + &addr6->mask); if (ret_val != 0) goto list_cb_failure; @@ -1266,11 +1425,8 @@ 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 list_head *iter_list; - struct netlbl_af4list *addr4; -#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) - struct netlbl_af6list *addr6; -#endif + struct netlbl_unlhsh_addr4 *addr4; + struct netlbl_unlhsh_addr6 *addr6; cb_arg.nl_cb = cb; cb_arg.skb = skb; @@ -1280,43 +1436,44 @@ 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) { - iter_list = &rcu_dereference(netlbl_unlhsh)->tbl[iter_bkt]; - list_for_each_entry_rcu(iface, iter_list, list) { + list_for_each_entry_rcu(iface, + &rcu_dereference(netlbl_unlhsh)->tbl[iter_bkt], + list) { if (!iface->valid || iter_chain++ < skip_chain) continue; - netlbl_af4list_foreach_rcu(addr4, - &iface->addr4_list) { - if (iter_addr4++ < skip_addr4) + list_for_each_entry_rcu(addr4, + &iface->addr4_list, + list) { + if (!addr4->valid || iter_addr4++ < skip_addr4) continue; if (netlbl_unlabel_staticlist_gen( - NLBL_UNLABEL_C_STATICLIST, - iface, - netlbl_unlhsh_addr4_entry(addr4), - NULL, - &cb_arg) < 0) { + NLBL_UNLABEL_C_STATICLIST, + iface, + addr4, + NULL, + &cb_arg) < 0) { iter_addr4--; iter_chain--; goto unlabel_staticlist_return; } } -#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) - netlbl_af6list_foreach_rcu(addr6, - &iface->addr6_list) { - if (iter_addr6++ < skip_addr6) + list_for_each_entry_rcu(addr6, + &iface->addr6_list, + list) { + if (!addr6->valid || iter_addr6++ < skip_addr6) continue; if (netlbl_unlabel_staticlist_gen( - NLBL_UNLABEL_C_STATICLIST, - iface, - NULL, - netlbl_unlhsh_addr6_entry(addr6), - &cb_arg) < 0) { + NLBL_UNLABEL_C_STATICLIST, + iface, + NULL, + addr6, + &cb_arg) < 0) { iter_addr6--; iter_chain--; goto unlabel_staticlist_return; } } -#endif /* IPv6 */ } } @@ -1347,12 +1504,9 @@ 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; - struct netlbl_af4list *addr4; -#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) - u32 iter_addr6 = 0; - struct netlbl_af6list *addr6; -#endif + u32 iter_addr4 = 0, iter_addr6 = 0; + struct netlbl_unlhsh_addr4 *addr4; + struct netlbl_unlhsh_addr6 *addr6; cb_arg.nl_cb = cb; cb_arg.skb = skb; @@ -1363,32 +1517,30 @@ static int netlbl_unlabel_staticlistdef(struct sk_buff *skb, if (iface == NULL || !iface->valid) goto unlabel_staticlistdef_return; - netlbl_af4list_foreach_rcu(addr4, &iface->addr4_list) { - if (iter_addr4++ < skip_addr4) + list_for_each_entry_rcu(addr4, &iface->addr4_list, list) { + if (!addr4->valid || iter_addr4++ < skip_addr4) continue; if (netlbl_unlabel_staticlist_gen(NLBL_UNLABEL_C_STATICLISTDEF, - iface, - netlbl_unlhsh_addr4_entry(addr4), - NULL, - &cb_arg) < 0) { + iface, + addr4, + NULL, + &cb_arg) < 0) { iter_addr4--; goto unlabel_staticlistdef_return; } } -#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) - netlbl_af6list_foreach_rcu(addr6, &iface->addr6_list) { - if (iter_addr6++ < skip_addr6) + list_for_each_entry_rcu(addr6, &iface->addr6_list, list) { + if (!addr6->valid || iter_addr6++ < skip_addr6) continue; if (netlbl_unlabel_staticlist_gen(NLBL_UNLABEL_C_STATICLISTDEF, - iface, - NULL, - netlbl_unlhsh_addr6_entry(addr6), - &cb_arg) < 0) { + iface, + NULL, + addr6, + &cb_arg) < 0) { iter_addr6--; goto unlabel_staticlistdef_return; } } -#endif /* IPv6 */ unlabel_staticlistdef_return: rcu_read_unlock(); @@ -1566,27 +1718,25 @@ int netlbl_unlabel_getattr(const struct sk_buff *skb, switch (family) { case PF_INET: { struct iphdr *hdr4; - struct netlbl_af4list *addr4; + struct netlbl_unlhsh_addr4 *addr4; hdr4 = ip_hdr(skb); - addr4 = netlbl_af4list_search(hdr4->saddr, - &iface->addr4_list); + addr4 = netlbl_unlhsh_search_addr4(hdr4->saddr, iface); if (addr4 == NULL) goto unlabel_getattr_nolabel; - secattr->attr.secid = netlbl_unlhsh_addr4_entry(addr4)->secid; + secattr->attr.secid = addr4->secid; break; } #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) case PF_INET6: { struct ipv6hdr *hdr6; - struct netlbl_af6list *addr6; + struct netlbl_unlhsh_addr6 *addr6; hdr6 = ipv6_hdr(skb); - addr6 = netlbl_af6list_search(&hdr6->saddr, - &iface->addr6_list); + addr6 = netlbl_unlhsh_search_addr6(&hdr6->saddr, iface); if (addr6 == NULL) goto unlabel_getattr_nolabel; - secattr->attr.secid = netlbl_unlhsh_addr6_entry(addr6)->secid; + secattr->attr.secid = addr6->secid; break; } #endif /* IPv6 */ diff --git a/trunk/scripts/mod/file2alias.c b/trunk/scripts/mod/file2alias.c index 473f94e56ead..4c9890ec2528 100644 --- a/trunk/scripts/mod/file2alias.c +++ b/trunk/scripts/mod/file2alias.c @@ -629,59 +629,6 @@ 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) { @@ -813,10 +760,6 @@ 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); } diff --git a/trunk/security/inode.c b/trunk/security/inode.c index efea5a605466..ca4958ebad8d 100644 --- a/trunk/security/inode.c +++ b/trunk/security/inode.c @@ -20,7 +20,8 @@ #include #include #include -#include + +#define SECURITYFS_MAGIC 0x73636673 static struct vfsmount *mount; static int mount_count; diff --git a/trunk/security/selinux/hooks.c b/trunk/security/selinux/hooks.c index 88f19536efad..4a7374c12d9c 100644 --- a/trunk/security/selinux/hooks.c +++ b/trunk/security/selinux/hooks.c @@ -291,7 +291,6 @@ 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); } @@ -2122,6 +2121,7 @@ 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,7 +3801,6 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in 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; @@ -3815,6 +3814,7 @@ 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,8 +3848,6 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, goto out; } - err = selinux_netlbl_socket_connect(sk, address); - out: return err; } @@ -4079,28 +4077,20 @@ 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, - u16 family) + struct avc_audit_data *ad, + u16 family, char *addrp) { 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; @@ -4109,14 +4099,12 @@ 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); - if (err) - selinux_netlbl_err(skb, err, 0); + SECCLASS_PEER, PEER__RECV, ad); } 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; @@ -4130,8 +4118,6 @@ 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; @@ -4140,18 +4126,6 @@ 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; @@ -4159,7 +4133,15 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) if (err) return err; - if (peerlbl_active) { + /* 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()) { u32 peer_sid; err = selinux_skb_peerlbl_sid(skb, family, &peer_sid); @@ -4167,17 +4149,13 @@ 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) { - selinux_netlbl_err(skb, err, 0); + if (err) return err; - } err = avc_has_perm(sk_sid, peer_sid, SECCLASS_PEER, PEER__RECV, &ad); - if (err) - selinux_netlbl_err(skb, err, 0); } - if (secmark_active) { + if (selinux_secmark_enabled()) { err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET, PACKET__RECV, &ad); if (err) @@ -4236,12 +4214,10 @@ static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff * u32 peer_secid = SECSID_NULL; u16 family; - 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) + if (sock) family = sock->sk->sk_family; + else if (skb && skb->sk) + family = skb->sk->sk_family; else goto out; @@ -4299,6 +4275,8 @@ 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, @@ -4306,15 +4284,10 @@ 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; - /* 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); + err = selinux_skb_peerlbl_sid(skb, sk->sk_family, &peersid); if (err) return err; if (peersid == SECSID_NULL) { @@ -4349,18 +4322,12 @@ 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; - /* 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); + selinux_skb_peerlbl_sid(skb, sk->sk_family, &sksec->peer_sid); } static void selinux_req_classify_flow(const struct request_sock *req, @@ -4410,54 +4377,39 @@ static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb) 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(); - netlbl_active = netlbl_enabled(); - peerlbl_active = netlbl_active || selinux_xfrm_enabled(); + peerlbl_active = netlbl_enabled() || 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 (peerlbl_active) { - err = selinux_inet_sys_rcv_skb(ifindex, addrp, family, - peer_sid, &ad); - if (err) { - selinux_netlbl_err(skb, err, 1); + 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) 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; } @@ -4481,37 +4433,6 @@ 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, @@ -4579,36 +4500,30 @@ static int selinux_ip_postroute_iptables_compat(struct sock *sk, static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb, int ifindex, - u16 family) + struct avc_audit_data *ad, + u16 family, + char *addrp, + u8 proto) { 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; @@ -4622,15 +4537,23 @@ 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, family); + return selinux_ip_postroute_compat(skb, ifindex, &ad, + family, addrp, proto); /* 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 @@ -4646,45 +4569,21 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex, if (!secmark_active && !peerlbl_active) return NF_ACCEPT; - /* 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 */ + /* 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 */ sk = skb->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 { + if (sk) { 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)) @@ -5758,13 +5657,6 @@ 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, } }; diff --git a/trunk/security/selinux/include/netlabel.h b/trunk/security/selinux/include/netlabel.h index b913c8d06038..487a7d81fe20 100644 --- a/trunk/security/selinux/include/netlabel.h +++ b/trunk/security/selinux/include/netlabel.h @@ -39,9 +39,6 @@ #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); @@ -49,11 +46,8 @@ 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_inet_conn_established(struct sock *sk, u16 family); +void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock); 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, @@ -63,27 +57,12 @@ 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) @@ -100,21 +79,9 @@ 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 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) +static inline void selinux_netlbl_sock_graft(struct sock *sk, + struct socket *sock) { return; } @@ -140,11 +107,6 @@ 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 diff --git a/trunk/security/selinux/include/objsec.h b/trunk/security/selinux/include/objsec.h index f8be8d7fa26d..91070ab874ce 100644 --- a/trunk/security/selinux/include/objsec.h +++ b/trunk/security/selinux/include/objsec.h @@ -109,19 +109,16 @@ 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 { diff --git a/trunk/security/selinux/netlabel.c b/trunk/security/selinux/netlabel.c index f58701a7b728..89b418392f11 100644 --- a/trunk/security/selinux/netlabel.c +++ b/trunk/security/selinux/netlabel.c @@ -9,7 +9,7 @@ */ /* - * (c) Copyright Hewlett-Packard Development Company, L.P., 2007, 2008 + * (c) Copyright Hewlett-Packard Development Company, L.P., 2007 * * 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 @@ -29,12 +29,8 @@ #include #include -#include -#include #include #include -#include -#include #include "objsec.h" #include "security.h" @@ -67,70 +63,33 @@ 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. Returns zero values - * on success, negative values on failure. + * Attempt to label a socket using the NetLabel mechanism using the given + * SID. Returns zero values on success, negative values on failure. * */ -static int selinux_netlbl_sock_setsid(struct sock *sk) +static int selinux_netlbl_sock_setsid(struct sock *sk, u32 sid) { int rc; struct sk_security_struct *sksec = sk->sk_security; - struct netlbl_lsm_secattr *secattr; + struct netlbl_lsm_secattr secattr; - if (sksec->nlbl_state != NLBL_REQUIRE) - return 0; + netlbl_secattr_init(&secattr); - secattr = selinux_netlbl_sock_genattr(sk); - if (secattr == NULL) - return -ENOMEM; - rc = netlbl_sock_setattr(sk, secattr); - switch (rc) { - case 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) 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; } @@ -146,38 +105,6 @@ 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 @@ -236,118 +163,35 @@ int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, } /** - * 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 + * selinux_netlbl_sock_graft - Netlabel the new socket * @sk: the new connection + * @sock: the new socket * * Description: - * A new connection has been established on @sk so make sure it is labeled - * correctly with the NetLabel susbsystem. + * The connection represented by @sk is being grafted onto @sock so set the + * socket's NetLabel to match the SID of @sk. * */ -void selinux_netlbl_inet_conn_established(struct sock *sk, u16 family) +void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock) { - int rc; struct sk_security_struct *sksec = sk->sk_security; - struct netlbl_lsm_secattr *secattr; - struct inet_sock *sk_inet = inet_sk(sk); - struct sockaddr_in addr; + struct netlbl_lsm_secattr secattr; + u32 nlbl_peer_sid; if (sksec->nlbl_state != NLBL_REQUIRE) return; - secattr = selinux_netlbl_sock_genattr(sk); - if (secattr == NULL) - 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); - 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; - } + /* 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); } /** @@ -361,7 +205,13 @@ void selinux_netlbl_inet_conn_established(struct sock *sk, u16 family) */ int selinux_netlbl_socket_post_create(struct socket *sock) { - return selinux_netlbl_sock_setsid(sock->sk); + 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); } /** @@ -396,7 +246,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); + rc = selinux_netlbl_sock_setsid(sk, sksec->sid); else rc = 0; bh_unlock_sock(sk); @@ -457,7 +307,7 @@ int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, return 0; if (nlbl_sid != SECINITSID_UNLABELED) - netlbl_skbuff_err(skb, rc, 0); + netlbl_skbuff_err(skb, rc); return rc; } @@ -484,8 +334,7 @@ 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_CONNLABELED)) { + sksec->nlbl_state == NLBL_LABELED) { netlbl_secattr_init(&secattr); lock_sock(sk); rc = netlbl_sock_getattr(sk, &secattr); @@ -497,50 +346,3 @@ 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; -} diff --git a/trunk/security/selinux/ss/services.c b/trunk/security/selinux/ss/services.c index 343c8ab14af0..ab0cc0c7b944 100644 --- a/trunk/security/selinux/ss/services.c +++ b/trunk/security/selinux/ss/services.c @@ -2955,7 +2955,7 @@ int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr, */ int security_netlbl_sid_to_secattr(u32 sid, struct netlbl_lsm_secattr *secattr) { - int rc; + int rc = -ENOENT; struct context *ctx; if (!ss_initialized) @@ -2963,18 +2963,11 @@ 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) { - rc = -ENOENT; + if (ctx == NULL) goto netlbl_sid_to_secattr_failure; - } secattr->domain = kstrdup(policydb.p_type_val_to_name[ctx->type - 1], GFP_ATOMIC); - 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; + secattr->flags |= NETLBL_SECATTR_DOMAIN_CPY; mls_export_netlbl_lvl(ctx, secattr); rc = mls_export_netlbl_cat(ctx, secattr); if (rc != 0) diff --git a/trunk/security/smack/smack_lsm.c b/trunk/security/smack/smack_lsm.c index 6e2dc0bab70d..87d75417ea93 100644 --- a/trunk/security/smack/smack_lsm.c +++ b/trunk/security/smack/smack_lsm.c @@ -2179,10 +2179,7 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) * This is the simplist possible security model * for networking. */ - rc = smk_access(smack, ssp->smk_in, MAY_WRITE); - if (rc != 0) - netlbl_skbuff_err(skb, rc, 0); - return rc; + return smk_access(smack, ssp->smk_in, MAY_WRITE); } /** diff --git a/trunk/security/smack/smackfs.c b/trunk/security/smack/smackfs.c index c21d8c8bf0c7..e7c642458ec9 100644 --- a/trunk/security/smack/smackfs.c +++ b/trunk/security/smack/smackfs.c @@ -354,11 +354,9 @@ 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); - } } /** diff --git a/trunk/sound/oss/ac97_codec.c b/trunk/sound/oss/ac97_codec.c index 456a1b4d7832..b63839e8f9bd 100644 --- a/trunk/sound/oss/ac97_codec.c +++ b/trunk/sound/oss/ac97_codec.c @@ -30,7 +30,7 @@ ************************************************************************** * * History - * May 02, 2003 Liam Girdwood + * May 02, 2003 Liam Girdwood * Removed non existant WM9700 * Added support for WM9705, WM9708, WM9709, WM9710, WM9711 * WM9712 and WM9717 diff --git a/trunk/sound/pci/ac97/ac97_patch.c b/trunk/sound/pci/ac97/ac97_patch.c index 6e831aff1bd0..6ce3cbe98a6a 100644 --- a/trunk/sound/pci/ac97/ac97_patch.c +++ b/trunk/sound/pci/ac97/ac97_patch.c @@ -476,7 +476,7 @@ static int patch_yamaha_ymf753(struct snd_ac97 * ac97) } /* - * May 2, 2003 Liam Girdwood + * May 2, 2003 Liam Girdwood * removed broken wolfson00 patch. * added support for WM9705,WM9708,WM9709,WM9710,WM9711,WM9712 and WM9717. */ diff --git a/trunk/sound/pci/hda/patch_sigmatel.c b/trunk/sound/pci/hda/patch_sigmatel.c index c59065513118..c461baa83c2a 100644 --- a/trunk/sound/pci/hda/patch_sigmatel.c +++ b/trunk/sound/pci/hda/patch_sigmatel.c @@ -322,8 +322,8 @@ static hda_nid_t stac92hd71bxx_mux_nids[2] = { 0x1a, 0x1b }; -static hda_nid_t stac92hd71bxx_dmux_nids[2] = { - 0x1c, 0x1d, +static hda_nid_t stac92hd71bxx_dmux_nids[1] = { + 0x1c, }; static hda_nid_t stac92hd71bxx_smux_nids[2] = { @@ -861,18 +861,20 @@ 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 2 +#define HD_DISABLE_PORTF 3 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 */ @@ -881,6 +883,10 @@ 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)}, @@ -1101,7 +1107,6 @@ 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), @@ -1114,17 +1119,8 @@ static struct snd_kcontrol_new stac92hd71bxx_analog_mixer[] = { HDA_CODEC_MUTE("PC Beep Switch", 0x17, 0x2, 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), + HDA_CODEC_MUTE("Analog Loopback 1", 0x17, 0x3, HDA_INPUT), + HDA_CODEC_MUTE("Analog Loopback 2", 0x17, 0x4, HDA_INPUT), { } /* end */ }; @@ -1653,7 +1649,7 @@ static struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = { static unsigned int ref92hd71bxx_pin_configs[11] = { 0x02214030, 0x02a19040, 0x01a19020, 0x01014010, - 0x0181302e, 0x01014010, 0x01019020, 0x90a000f0, + 0x0181302e, 0x01114010, 0x01019020, 0x90a000f0, 0x90a000f0, 0x01452050, 0x01452050, }; @@ -3004,7 +3000,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 */ @@ -4331,16 +4327,6 @@ 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; @@ -4355,8 +4341,6 @@ 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, @@ -4408,7 +4392,6 @@ static int patch_stac92hd71bxx(struct hda_codec *codec) /* 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]; @@ -4426,13 +4409,12 @@ static int patch_stac92hd71bxx(struct hda_codec *codec) 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 = 0x50; + spec->aloopback_mask = 0x20; spec->aloopback_shift = 0; if (spec->board_config > STAC_92HD71BXX_REF) { @@ -4474,10 +4456,6 @@ static int patch_stac92hd71bxx(struct hda_codec *codec) 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) { diff --git a/trunk/sound/soc/at91/Kconfig b/trunk/sound/soc/at91/Kconfig index 85a883299c2e..905186502e00 100644 --- a/trunk/sound/soc/at91/Kconfig +++ b/trunk/sound/soc/at91/Kconfig @@ -8,3 +8,20 @@ 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. diff --git a/trunk/sound/soc/at91/Makefile b/trunk/sound/soc/at91/Makefile index b817f11df286..f23da17cc328 100644 --- a/trunk/sound/soc/at91/Makefile +++ b/trunk/sound/soc/at91/Makefile @@ -4,3 +4,8 @@ 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 diff --git a/trunk/sound/soc/at91/at91-ssc.c b/trunk/sound/soc/at91/at91-ssc.c index 1b61cc461261..a5b1a79ebffb 100644 --- a/trunk/sound/soc/at91/at91-ssc.c +++ b/trunk/sound/soc/at91/at91-ssc.c @@ -5,7 +5,7 @@ * Endrelia Technologies Inc. * * Based on pxa2xx Platform drivers by - * Liam Girdwood + * Liam Girdwood * * 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/trunk/sound/soc/at91/eti_b1_wm8731.c b/trunk/sound/soc/at91/eti_b1_wm8731.c new file mode 100644 index 000000000000..684781e4088b --- /dev/null +++ b/trunk/sound/soc/at91/eti_b1_wm8731.c @@ -0,0 +1,349 @@ +/* + * eti_b1_wm8731 -- SoC audio for AT91RM9200-based Endrelia ETI_B1 board. + * + * Author: Frank Mandarino + * Endrelia Technologies Inc. + * Created: Mar 29, 2006 + * + * Based on corgi.c by: + * + * Copyright 2005 Wolfson Microelectronics PLC. + * Copyright 2005 Openedhand Ltd. + * + * Authors: Liam Girdwood + * Richard Purdie + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#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 "); +MODULE_DESCRIPTION("ALSA SoC ETI-B1-WM8731"); +MODULE_LICENSE("GPL"); diff --git a/trunk/sound/soc/blackfin/Kconfig b/trunk/sound/soc/blackfin/Kconfig index dc006206f622..f98331d099e7 100644 --- a/trunk/sound/soc/blackfin/Kconfig +++ b/trunk/sound/soc/blackfin/Kconfig @@ -17,22 +17,6 @@ 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 diff --git a/trunk/sound/soc/blackfin/Makefile b/trunk/sound/soc/blackfin/Makefile index 97bb37a6359c..9ea8bd9e0ba3 100644 --- a/trunk/sound/soc/blackfin/Makefile +++ b/trunk/sound/soc/blackfin/Makefile @@ -14,8 +14,7 @@ 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 diff --git a/trunk/sound/soc/blackfin/bf5xx-ac97-pcm.c b/trunk/sound/soc/blackfin/bf5xx-ac97-pcm.c index 25e50d2ea1ec..51f4907c4831 100644 --- a/trunk/sound/soc/blackfin/bf5xx-ac97-pcm.c +++ b/trunk/sound/soc/blackfin/bf5xx-ac97-pcm.c @@ -56,7 +56,6 @@ 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, @@ -73,15 +72,7 @@ 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); } @@ -123,10 +114,6 @@ 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; } @@ -140,11 +127,16 @@ 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)); @@ -172,12 +164,8 @@ 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) { - bf5xx_mmap_copy(substream, runtime->period_size); - snd_pcm_period_elapsed(substream); - sport->tx_delay_pos = 0; + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) sport_tx_start(sport); - } else sport_rx_start(sport); break; @@ -210,7 +198,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_delay_pos; + curr = sport->tx_pos; else curr = sport->rx_pos; #else @@ -249,21 +237,6 @@ 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) @@ -299,7 +272,6 @@ 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, diff --git a/trunk/sound/soc/blackfin/bf5xx-ac97.c b/trunk/sound/soc/blackfin/bf5xx-ac97.c index 5e5aafb6485f..c782e311fd56 100644 --- a/trunk/sound/soc/blackfin/bf5xx-ac97.c +++ b/trunk/sound/soc/blackfin/bf5xx-ac97.c @@ -128,6 +128,7 @@ 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/trunk/sound/soc/blackfin/bf5xx-ad73311.c b/trunk/sound/soc/blackfin/bf5xx-ad73311.c deleted file mode 100644 index 622c9b909532..000000000000 --- a/trunk/sound/soc/blackfin/bf5xx-ad73311.c +++ /dev/null @@ -1,240 +0,0 @@ -/* - * File: sound/soc/blackfin/bf5xx-ad73311.c - * Author: Cliff Cai - * - * 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 -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#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"); - diff --git a/trunk/sound/soc/blackfin/bf5xx-i2s.c b/trunk/sound/soc/blackfin/bf5xx-i2s.c index 827587f08180..43a4092eeb89 100644 --- a/trunk/sound/soc/blackfin/bf5xx-i2s.c +++ b/trunk/sound/soc/blackfin/bf5xx-i2s.c @@ -70,13 +70,6 @@ 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) { @@ -85,14 +78,6 @@ 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; @@ -142,17 +127,14 @@ 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; } @@ -163,17 +145,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:slave mode. + * CPU DAI format:I2S, slave mode. */ - ret = sport_config_rx(sport_handle, bf5xx_i2s.rcr1, - bf5xx_i2s.rcr2, 0, 0); + ret = sport_config_rx(sport_handle, RFSR | RCKFE, + RSFSE|bf5xx_i2s.rcr2, 0, 0); if (ret) { pr_err("SPORT is busy!\n"); return -EBUSY; } - ret = sport_config_tx(sport_handle, bf5xx_i2s.tcr1, - bf5xx_i2s.tcr2, 0, 0); + ret = sport_config_tx(sport_handle, TFSR | TCKFE, + TSFSE|bf5xx_i2s.tcr2, 0, 0); if (ret) { pr_err("SPORT is busy!\n"); return -EBUSY; @@ -192,6 +174,13 @@ 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"); @@ -209,13 +198,6 @@ 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) @@ -281,16 +263,15 @@ 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 = 1, + .channels_min = 2, .channels_max = 2, .rates = BF5XX_I2S_RATES, .formats = BF5XX_I2S_FORMATS,}, .capture = { - .channels_min = 1, + .channels_min = 2, .channels_max = 2, .rates = BF5XX_I2S_RATES, .formats = BF5XX_I2S_FORMATS,}, diff --git a/trunk/sound/soc/blackfin/bf5xx-sport.h b/trunk/sound/soc/blackfin/bf5xx-sport.h index fcadcc081f7f..4c163454bbf8 100644 --- a/trunk/sound/soc/blackfin/bf5xx-sport.h +++ b/trunk/sound/soc/blackfin/bf5xx-sport.h @@ -123,8 +123,6 @@ 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; }; diff --git a/trunk/sound/soc/codecs/Kconfig b/trunk/sound/soc/codecs/Kconfig index 4975d8573e4f..e0b9869df0f1 100644 --- a/trunk/sound/soc/codecs/Kconfig +++ b/trunk/sound/soc/codecs/Kconfig @@ -3,11 +3,9 @@ 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 @@ -36,9 +34,6 @@ config SND_SOC_AC97_CODEC config SND_SOC_AD1980 tristate -config SND_SOC_AD73311 - tristate - config SND_SOC_AK4535 tristate @@ -63,13 +58,9 @@ 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 SPI + depends on SND_SOC && SPI config SND_SOC_TLV320AIC3X tristate diff --git a/trunk/sound/soc/codecs/Makefile b/trunk/sound/soc/codecs/Makefile index 90f0a585fc70..f977978a3409 100644 --- a/trunk/sound/soc/codecs/Makefile +++ b/trunk/sound/soc/codecs/Makefile @@ -1,10 +1,8 @@ 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 @@ -22,11 +20,9 @@ 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 diff --git a/trunk/sound/soc/codecs/ac97.c b/trunk/sound/soc/codecs/ac97.c index bd1ebdc6c86c..61fd96ca7bc7 100644 --- a/trunk/sound/soc/codecs/ac97.c +++ b/trunk/sound/soc/codecs/ac97.c @@ -2,7 +2,8 @@ * ac97.c -- ALSA Soc AC97 codec support * * Copyright 2005 Wolfson Microelectronics PLC. - * Author: Liam Girdwood + * Author: Liam Girdwood + * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.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 diff --git a/trunk/sound/soc/codecs/ad1980.c b/trunk/sound/soc/codecs/ad1980.c index 1397b8e06c0b..4e09c1f2c063 100644 --- a/trunk/sound/soc/codecs/ad1980.c +++ b/trunk/sound/soc/codecs/ad1980.c @@ -13,6 +13,7 @@ #include #include +#include #include #include #include diff --git a/trunk/sound/soc/codecs/ad73311.c b/trunk/sound/soc/codecs/ad73311.c deleted file mode 100644 index 37af8607b00a..000000000000 --- a/trunk/sound/soc/codecs/ad73311.c +++ /dev/null @@ -1,107 +0,0 @@ -/* - * ad73311.c -- ALSA Soc AD73311 codec support - * - * Copyright: Analog Device Inc. - * Author: Cliff Cai - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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/trunk/sound/soc/codecs/ad73311.h b/trunk/sound/soc/codecs/ad73311.h deleted file mode 100644 index 507ce0c30edf..000000000000 --- a/trunk/sound/soc/codecs/ad73311.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * File: sound/soc/codec/ad73311.h - * Based on: - * Author: Cliff Cai - * - * 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 diff --git a/trunk/sound/soc/codecs/ak4535.c b/trunk/sound/soc/codecs/ak4535.c index 2a89b5888e11..088cf9927720 100644 --- a/trunk/sound/soc/codecs/ak4535.c +++ b/trunk/sound/soc/codecs/ak4535.c @@ -28,6 +28,7 @@ #include "ak4535.h" +#define AUDIO_NAME "ak4535" #define AK4535_VERSION "0.3" struct snd_soc_codec_device soc_codec_dev_ak4535; diff --git a/trunk/sound/soc/codecs/ssm2602.c b/trunk/sound/soc/codecs/ssm2602.c index 44ef0dacd564..940ce1c3522e 100644 --- a/trunk/sound/soc/codecs/ssm2602.c +++ b/trunk/sound/soc/codecs/ssm2602.c @@ -42,6 +42,7 @@ #include "ssm2602.h" +#define AUDIO_NAME "ssm2602" #define SSM2602_VERSION "0.1" struct snd_soc_codec_device soc_codec_dev_ssm2602; diff --git a/trunk/sound/soc/codecs/tlv320aic23.c b/trunk/sound/soc/codecs/tlv320aic23.c deleted file mode 100644 index bac7815e00fb..000000000000 --- a/trunk/sound/soc/codecs/tlv320aic23.c +++ /dev/null @@ -1,714 +0,0 @@ -/* - * ALSA SoC TLV320AIC23 codec driver - * - * Author: Arun KS, - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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 "); -MODULE_LICENSE("GPL"); diff --git a/trunk/sound/soc/codecs/tlv320aic23.h b/trunk/sound/soc/codecs/tlv320aic23.h deleted file mode 100644 index 79d1faf8e570..000000000000 --- a/trunk/sound/soc/codecs/tlv320aic23.h +++ /dev/null @@ -1,122 +0,0 @@ -/* - * ALSA SoC TLV320AIC23 codec driver - * - * Author: Arun KS, - * 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 */ diff --git a/trunk/sound/soc/codecs/tlv320aic3x.c b/trunk/sound/soc/codecs/tlv320aic3x.c index 05336ed7e493..566a427c928f 100644 --- a/trunk/sound/soc/codecs/tlv320aic3x.c +++ b/trunk/sound/soc/codecs/tlv320aic3x.c @@ -48,6 +48,7 @@ #include "tlv320aic3x.h" +#define AUDIO_NAME "aic3x" #define AIC3X_VERSION "0.2" /* codec private data */ @@ -990,7 +991,7 @@ EXPORT_SYMBOL_GPL(aic3x_headset_detected); SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE) struct snd_soc_dai aic3x_dai = { - .name = "tlv320aic3x", + .name = "aic3x", .playback = { .stream_name = "Playback", .channels_min = 1, @@ -1054,7 +1055,7 @@ static int aic3x_init(struct snd_soc_device *socdev) struct aic3x_setup_data *setup = socdev->codec_data; int reg, ret = 0; - codec->name = "tlv320aic3x"; + codec->name = "aic3x"; codec->owner = THIS_MODULE; codec->read = aic3x_read_reg_cache; codec->write = aic3x_write; diff --git a/trunk/sound/soc/codecs/uda1380.c b/trunk/sound/soc/codecs/uda1380.c index a69ee72a7af5..d206d7f892b6 100644 --- a/trunk/sound/soc/codecs/uda1380.c +++ b/trunk/sound/soc/codecs/uda1380.c @@ -36,6 +36,7 @@ #include "uda1380.h" #define UDA1380_VERSION "0.6" +#define AUDIO_NAME "uda1380" /* * uda1380 register cache diff --git a/trunk/sound/soc/codecs/wm8510.c b/trunk/sound/soc/codecs/wm8510.c index d8ca2da8d634..9a37c8d95ed2 100644 --- a/trunk/sound/soc/codecs/wm8510.c +++ b/trunk/sound/soc/codecs/wm8510.c @@ -3,7 +3,7 @@ * * Copyright 2006 Wolfson Microelectronics PLC. * - * Author: Liam Girdwood + * Author: Liam Girdwood * * 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,7 +18,6 @@ #include #include #include -#include #include #include #include @@ -28,6 +27,7 @@ #include "wm8510.h" +#define AUDIO_NAME "wm8510" #define WM8510_VERSION "0.6" struct snd_soc_codec_device soc_codec_dev_wm8510; @@ -55,9 +55,6 @@ static const u16 wm8510_reg[WM8510_CACHEREGNUM] = { 0x0001, }; -#define WM8510_POWER1_BIASEN 0x08 -#define WM8510_POWER1_BUFIOEN 0x10 - /* * read wm8510 register cache */ @@ -227,9 +224,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_MIXER("Mic PGA", WM8510_POWER2, 2, 0, - &wm8510_micpga_controls[0], - ARRAY_SIZE(wm8510_micpga_controls)), +SND_SOC_DAPM_PGA("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)), @@ -529,35 +526,23 @@ 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: - case SND_SOC_BIAS_PREPARE: - power1 |= 0x1; /* VMID 50k */ - wm8510_write(codec, WM8510_POWER1, power1); + wm8510_write(codec, WM8510_POWER1, 0x1ff); + wm8510_write(codec, WM8510_POWER2, 0x1ff); + wm8510_write(codec, WM8510_POWER3, 0x1ff); break; - + case SND_SOC_BIAS_PREPARE: 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: - wm8510_write(codec, WM8510_POWER1, 0); - wm8510_write(codec, WM8510_POWER2, 0); - wm8510_write(codec, WM8510_POWER3, 0); + /* everything off, dac mute, inactive */ + wm8510_write(codec, WM8510_POWER1, 0x0); + wm8510_write(codec, WM8510_POWER2, 0x0); + wm8510_write(codec, WM8510_POWER3, 0x0); break; } - codec->bias_level = level; return 0; } @@ -655,7 +640,6 @@ 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); @@ -763,62 +747,6 @@ static int wm8510_add_i2c_device(struct platform_device *pdev, } #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); @@ -844,14 +772,8 @@ static int wm8510_probe(struct platform_device *pdev) codec->hw_write = (hw_write_t)i2c_master_send; ret = wm8510_add_i2c_device(pdev, setup); } -#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"); - } +#else + /* Add other interfaces here */ #endif if (ret != 0) @@ -873,9 +795,6 @@ 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); diff --git a/trunk/sound/soc/codecs/wm8510.h b/trunk/sound/soc/codecs/wm8510.h index bdefcf5c69ff..c53683960456 100644 --- a/trunk/sound/soc/codecs/wm8510.h +++ b/trunk/sound/soc/codecs/wm8510.h @@ -94,7 +94,6 @@ #define WM8510_MCLKDIV_12 (7 << 5) struct wm8510_setup_data { - int spi; int i2c_bus; unsigned short i2c_address; }; diff --git a/trunk/sound/soc/codecs/wm8580.c b/trunk/sound/soc/codecs/wm8580.c index 627ebfb4209b..df1ffbe305bf 100644 --- a/trunk/sound/soc/codecs/wm8580.c +++ b/trunk/sound/soc/codecs/wm8580.c @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -35,6 +36,7 @@ #include "wm8580.h" +#define AUDIO_NAME "wm8580" #define WM8580_VERSION "0.1" struct pll_state { diff --git a/trunk/sound/soc/codecs/wm8731.c b/trunk/sound/soc/codecs/wm8731.c index 7f8a7e36b33e..7b64d9a7ff76 100644 --- a/trunk/sound/soc/codecs/wm8731.c +++ b/trunk/sound/soc/codecs/wm8731.c @@ -29,6 +29,7 @@ #include "wm8731.h" +#define AUDIO_NAME "wm8731" #define WM8731_VERSION "0.13" struct snd_soc_codec_device soc_codec_dev_wm8731; diff --git a/trunk/sound/soc/codecs/wm8750.c b/trunk/sound/soc/codecs/wm8750.c index 9b7296ee5b08..4892e398a598 100644 --- a/trunk/sound/soc/codecs/wm8750.c +++ b/trunk/sound/soc/codecs/wm8750.c @@ -29,6 +29,7 @@ #include "wm8750.h" +#define AUDIO_NAME "WM8750" #define WM8750_VERSION "0.12" /* codec private data */ diff --git a/trunk/sound/soc/codecs/wm8753.c b/trunk/sound/soc/codecs/wm8753.c index d426eaa22185..8c4df44f3345 100644 --- a/trunk/sound/soc/codecs/wm8753.c +++ b/trunk/sound/soc/codecs/wm8753.c @@ -2,7 +2,8 @@ * wm8753.c -- WM8753 ALSA Soc Audio driver * * Copyright 2003 Wolfson Microelectronics PLC. - * Author: Liam Girdwood + * Author: Liam Girdwood + * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.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 @@ -39,7 +40,6 @@ #include #include #include -#include #include #include #include @@ -51,6 +51,7 @@ #include "wm8753.h" +#define AUDIO_NAME "wm8753" #define WM8753_VERSION "0.16" static int caps_charge = 2000; @@ -1718,63 +1719,6 @@ static int wm8753_add_i2c_device(struct platform_device *pdev, } #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); @@ -1809,14 +1753,8 @@ static int wm8753_probe(struct platform_device *pdev) codec->hw_write = (hw_write_t)i2c_master_send; ret = wm8753_add_i2c_device(pdev, setup); } -#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"); - } +#else + /* Add other interfaces here */ #endif if (ret != 0) { @@ -1859,9 +1797,6 @@ 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); diff --git a/trunk/sound/soc/codecs/wm8753.h b/trunk/sound/soc/codecs/wm8753.h index f55704ce931b..7defde069f1d 100644 --- a/trunk/sound/soc/codecs/wm8753.h +++ b/trunk/sound/soc/codecs/wm8753.h @@ -2,7 +2,8 @@ * wm8753.h -- audio driver for WM8753 * * Copyright 2003 Wolfson Microelectronics PLC. - * Author: Liam Girdwood + * Author: Liam Girdwood + * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.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 @@ -78,7 +79,6 @@ #define WM8753_ADCTL2 0x3f struct wm8753_setup_data { - int spi; int i2c_bus; unsigned short i2c_address; }; diff --git a/trunk/sound/soc/codecs/wm8900.c b/trunk/sound/soc/codecs/wm8900.c index 3b326c9b5586..0b8c6d38b48f 100644 --- a/trunk/sound/soc/codecs/wm8900.c +++ b/trunk/sound/soc/codecs/wm8900.c @@ -18,6 +18,7 @@ #include #include +#include #include #include #include diff --git a/trunk/sound/soc/codecs/wm8903.c b/trunk/sound/soc/codecs/wm8903.c index ce40d7877605..a3f54ec4226e 100644 --- a/trunk/sound/soc/codecs/wm8903.c +++ b/trunk/sound/soc/codecs/wm8903.c @@ -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, 1), + 7, 1, 0), 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, 1), + 7, 1, 0), 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, diff --git a/trunk/sound/soc/codecs/wm8971.c b/trunk/sound/soc/codecs/wm8971.c index f41a578ddd4f..974a4cd0f3fd 100644 --- a/trunk/sound/soc/codecs/wm8971.c +++ b/trunk/sound/soc/codecs/wm8971.c @@ -29,6 +29,7 @@ #include "wm8971.h" +#define AUDIO_NAME "wm8971" #define WM8971_VERSION "0.9" #define WM8971_REG_COUNT 43 diff --git a/trunk/sound/soc/codecs/wm8990.c b/trunk/sound/soc/codecs/wm8990.c index 572d22b0880b..63410d7b5efb 100644 --- a/trunk/sound/soc/codecs/wm8990.c +++ b/trunk/sound/soc/codecs/wm8990.c @@ -30,6 +30,7 @@ #include "wm8990.h" +#define AUDIO_NAME "wm8990" #define WM8990_VERSION "0.2" /* codec private data */ diff --git a/trunk/sound/soc/codecs/wm9712.c b/trunk/sound/soc/codecs/wm9712.c index ffb471e420e2..2f1c91b1d556 100644 --- a/trunk/sound/soc/codecs/wm9712.c +++ b/trunk/sound/soc/codecs/wm9712.c @@ -2,7 +2,8 @@ * wm9712.c -- ALSA Soc WM9712 codec support * * Copyright 2006 Wolfson Microelectronics PLC. - * Author: Liam Girdwood + * Author: Liam Girdwood + * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.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 diff --git a/trunk/sound/soc/codecs/wm9713.c b/trunk/sound/soc/codecs/wm9713.c index aba402b3c999..441d0580db1f 100644 --- a/trunk/sound/soc/codecs/wm9713.c +++ b/trunk/sound/soc/codecs/wm9713.c @@ -2,7 +2,8 @@ * wm9713.c -- ALSA Soc WM9713 codec support * * Copyright 2006 Wolfson Microelectronics PLC. - * Author: Liam Girdwood + * Author: Liam Girdwood + * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.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 diff --git a/trunk/sound/soc/omap/Kconfig b/trunk/sound/soc/omap/Kconfig index 8b7766b998d7..aea27e70043c 100644 --- a/trunk/sound/soc/omap/Kconfig +++ b/trunk/sound/soc/omap/Kconfig @@ -13,11 +13,3 @@ 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. diff --git a/trunk/sound/soc/omap/Makefile b/trunk/sound/soc/omap/Makefile index e09d1f297f64..d8d8d58075e3 100644 --- a/trunk/sound/soc/omap/Makefile +++ b/trunk/sound/soc/omap/Makefile @@ -7,7 +7,5 @@ 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 diff --git a/trunk/sound/soc/omap/n810.c b/trunk/sound/soc/omap/n810.c index fae3ad36e0bf..d166b6b2a60d 100644 --- a/trunk/sound/soc/omap/n810.c +++ b/trunk/sound/soc/omap/n810.c @@ -247,9 +247,9 @@ static int n810_aic33_init(struct snd_soc_codec *codec) int i, err; /* Not connected */ - snd_soc_dapm_nc_pin(codec, "MONO_LOUT"); - snd_soc_dapm_nc_pin(codec, "HPLCOM"); - snd_soc_dapm_nc_pin(codec, "HPRCOM"); + snd_soc_dapm_disable_pin(codec, "MONO_LOUT"); + snd_soc_dapm_disable_pin(codec, "HPLCOM"); + snd_soc_dapm_disable_pin(codec, "HPRCOM"); /* Add N810 specific controls */ for (i = 0; i < ARRAY_SIZE(aic33_n810_controls); i++) { diff --git a/trunk/sound/soc/omap/omap-mcbsp.c b/trunk/sound/soc/omap/omap-mcbsp.c index 0a063a98a661..35310e16d7f3 100644 --- a/trunk/sound/soc/omap/omap-mcbsp.c +++ b/trunk/sound/soc/omap/omap-mcbsp.c @@ -59,7 +59,12 @@ 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]; +static struct omap_pcm_dma_data omap_mcbsp_dai_dma_params[NUM_LINKS][2] = { +{ + { .name = "I2S PCM Stereo out", }, + { .name = "I2S PCM Stereo in", }, +}, +}; #if defined(CONFIG_ARCH_OMAP15XX) || defined(CONFIG_ARCH_OMAP16XX) static const int omap1_dma_reqs[][2] = { @@ -79,22 +84,11 @@ 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_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) -static const int omap24xx_dma_reqs[][2] = { +#if defined(CONFIG_ARCH_OMAP2420) +static const int omap2420_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 }, @@ -102,43 +96,10 @@ 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; @@ -206,19 +167,14 @@ 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 = omap24xx_dma_reqs[bus_id][substream->stream]; + dma = omap2420_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]; @@ -289,11 +245,6 @@ 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; @@ -359,7 +310,7 @@ static int omap_mcbsp_dai_set_clks_src(struct omap_mcbsp_data *mcbsp_data, int clk_id) { int sel_bit; - u16 reg, reg_devconf1 = OMAP243X_CONTROL_DEVCONF1; + u16 reg; if (cpu_class_is_omap1()) { /* OMAP1's can use only external source clock */ @@ -369,12 +320,6 @@ 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; @@ -384,26 +329,20 @@ static int omap_mcbsp_dai_set_clks_src(struct omap_mcbsp_data *mcbsp_data, reg = OMAP2_CONTROL_DEVCONF0; sel_bit = 6; break; - 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; + /* TODO: Support for ports 3 - 5 in OMAP2430 and OMAP34xx */ default: return -EINVAL; } - 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 (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); + } + } return 0; } @@ -437,49 +376,37 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, return err; } -#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 +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, +}, }; - EXPORT_SYMBOL_GPL(omap_mcbsp_dai); MODULE_AUTHOR("Jarkko Nikula "); diff --git a/trunk/sound/soc/omap/omap-mcbsp.h b/trunk/sound/soc/omap/omap-mcbsp.h index df7ad13ba73d..ed8afb550671 100644 --- a/trunk/sound/soc/omap/omap-mcbsp.h +++ b/trunk/sound/soc/omap/omap-mcbsp.h @@ -38,17 +38,11 @@ enum omap_mcbsp_div { OMAP_MCBSP_CLKGDV, /* Sample rate generator divider */ }; -#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 +/* + * 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 extern struct snd_soc_dai omap_mcbsp_dai[NUM_LINKS]; diff --git a/trunk/sound/soc/omap/omap-pcm.c b/trunk/sound/soc/omap/omap-pcm.c index e9084fdd2082..690bfeaec4a0 100644 --- a/trunk/sound/soc/omap/omap-pcm.c +++ b/trunk/sound/soc/omap/omap-pcm.c @@ -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 (!err & !cpu_is_omap1510()) { + if (!cpu_is_omap1510()) { /* * Link channel with itself so DMA doesn't need any * reprogramming while looping the buffer @@ -147,14 +147,12 @@ 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/trunk/sound/soc/omap/osk5912.c b/trunk/sound/soc/omap/osk5912.c deleted file mode 100644 index 0fe733796898..000000000000 --- a/trunk/sound/soc/omap/osk5912.c +++ /dev/null @@ -1,232 +0,0 @@ -/* - * osk5912.c -- SoC audio for OSK 5912 - * - * Copyright (C) 2008 Mistral Solutions - * - * Contact: Arun KS - * - * 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 -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#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 "); -MODULE_DESCRIPTION("ALSA SoC OSK 5912"); -MODULE_LICENSE("GPL"); diff --git a/trunk/sound/soc/pxa/corgi.c b/trunk/sound/soc/pxa/corgi.c index 2718eaf7895f..1a8373de7f3a 100644 --- a/trunk/sound/soc/pxa/corgi.c +++ b/trunk/sound/soc/pxa/corgi.c @@ -4,7 +4,7 @@ * Copyright 2005 Wolfson Microelectronics PLC. * Copyright 2005 Openedhand Ltd. * - * Authors: Liam Girdwood + * Authors: Liam Girdwood * Richard Purdie * * 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_nc_pin(codec, "LLINEIN"); - snd_soc_dapm_nc_pin(codec, "RLINEIN"); + snd_soc_dapm_disable_pin(codec, "LLINEIN"); + snd_soc_dapm_disable_pin(codec, "RLINEIN"); /* Add corgi specific controls */ for (i = 0; i < ARRAY_SIZE(wm8731_corgi_controls); i++) { diff --git a/trunk/sound/soc/pxa/em-x270.c b/trunk/sound/soc/pxa/em-x270.c index e6ff6929ab4b..d9c3f7b28be2 100644 --- a/trunk/sound/soc/pxa/em-x270.c +++ b/trunk/sound/soc/pxa/em-x270.c @@ -9,7 +9,7 @@ * Copyright 2005 Wolfson Microelectronics PLC. * Copyright 2005 Openedhand Ltd. * - * Authors: Liam Girdwood + * Authors: Liam Girdwood * Richard Purdie * * This program is free software; you can redistribute it and/or modify it diff --git a/trunk/sound/soc/pxa/poodle.c b/trunk/sound/soc/pxa/poodle.c index 4d9930c52789..f84f7d8db09a 100644 --- a/trunk/sound/soc/pxa/poodle.c +++ b/trunk/sound/soc/pxa/poodle.c @@ -4,7 +4,7 @@ * Copyright 2005 Wolfson Microelectronics PLC. * Copyright 2005 Openedhand Ltd. * - * Authors: Liam Girdwood + * Authors: Liam Girdwood * Richard Purdie * * 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_nc_pin(codec, "LLINEIN"); - snd_soc_dapm_nc_pin(codec, "RLINEIN"); + snd_soc_dapm_disable_pin(codec, "LLINEIN"); + snd_soc_dapm_disable_pin(codec, "RLINEIN"); snd_soc_dapm_enable_pin(codec, "MICIN"); /* Add poodle specific controls */ diff --git a/trunk/sound/soc/pxa/pxa2xx-i2s.c b/trunk/sound/soc/pxa/pxa2xx-i2s.c index e758034db5c3..2fb58298513b 100644 --- a/trunk/sound/soc/pxa/pxa2xx-i2s.c +++ b/trunk/sound/soc/pxa/pxa2xx-i2s.c @@ -3,7 +3,7 @@ * * Copyright 2005 Wolfson Microelectronics PLC. * Author: Liam Girdwood - * lrg@slimlogic.co.uk + * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.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 @@ -405,6 +405,6 @@ module_init(pxa2xx_i2s_init); module_exit(pxa2xx_i2s_exit); /* Module information */ -MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk"); +MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com"); MODULE_DESCRIPTION("pxa2xx I2S SoC Interface"); MODULE_LICENSE("GPL"); diff --git a/trunk/sound/soc/pxa/spitz.c b/trunk/sound/soc/pxa/spitz.c index d307b6757e95..9a70b00fc30e 100644 --- a/trunk/sound/soc/pxa/spitz.c +++ b/trunk/sound/soc/pxa/spitz.c @@ -4,7 +4,7 @@ * Copyright 2005 Wolfson Microelectronics PLC. * Copyright 2005 Openedhand Ltd. * - * Authors: Liam Girdwood + * Authors: Liam Girdwood * Richard Purdie * * 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_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"); + 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"); /* Add spitz specific controls */ for (i = 0; i < ARRAY_SIZE(wm8750_spitz_controls); i++) { diff --git a/trunk/sound/soc/pxa/tosa.c b/trunk/sound/soc/pxa/tosa.c index afefe41b8c46..2baaa750f123 100644 --- a/trunk/sound/soc/pxa/tosa.c +++ b/trunk/sound/soc/pxa/tosa.c @@ -4,7 +4,7 @@ * Copyright 2005 Wolfson Microelectronics PLC. * Copyright 2005 Openedhand Ltd. * - * Authors: Liam Girdwood + * Authors: Liam Girdwood * Richard Purdie * * 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_nc_pin(codec, "OUT3"); - snd_soc_dapm_nc_pin(codec, "MONOOUT"); + snd_soc_dapm_disable_pin(codec, "OUT3"); + snd_soc_dapm_disable_pin(codec, "MONOOUT"); /* add tosa specific controls */ for (i = 0; i < ARRAY_SIZE(tosa_controls); i++) { diff --git a/trunk/sound/soc/s3c24xx/neo1973_wm8753.c b/trunk/sound/soc/s3c24xx/neo1973_wm8753.c index 87ddfefcc2fb..73a50e93a9a2 100644 --- a/trunk/sound/soc/s3c24xx/neo1973_wm8753.c +++ b/trunk/sound/soc/s3c24xx/neo1973_wm8753.c @@ -511,20 +511,21 @@ static int neo1973_wm8753_init(struct snd_soc_codec *codec) DBG("Entered %s\n", __func__); /* set up NC codec pins */ - 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"); + 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"); - /* 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 widgets */ + snd_soc_dapm_new_controls(codec, wm8753_dapm_widgets, + ARRAY_SIZE(wm8753_dapm_widgets)); + /* add neo1973 specific controls */ for (i = 0; i < ARRAY_SIZE(wm8753_neo1973_controls); i++) { err = snd_ctl_add(codec->card, @@ -602,8 +603,6 @@ static int lm4857_i2c_probe(struct i2c_client *client, { DBG("Entered %s\n", __func__); - i2c = client; - lm4857_write_regs(); return 0; } @@ -612,8 +611,6 @@ static int lm4857_i2c_remove(struct i2c_client *client) { DBG("Entered %s\n", __func__); - i2c = NULL; - return 0; } @@ -653,7 +650,7 @@ static void lm4857_shutdown(struct i2c_client *dev) } static const struct i2c_device_id lm4857_i2c_id[] = { - { "neo1973_lm4857", 0 }, + { "neo1973_lm4857", 0 } { } }; @@ -671,6 +668,48 @@ 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) { @@ -697,8 +736,8 @@ static int __init neo1973_init(void) return ret; } - ret = i2c_add_driver(&lm4857_i2c_driver); - + ret = neo1973_add_lm4857_device(neo1973_snd_device, + neo1973_wm8753_setup, 0x7C); if (ret != 0) platform_device_unregister(neo1973_snd_device); @@ -709,6 +748,7 @@ 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); } diff --git a/trunk/sound/soc/soc-core.c b/trunk/sound/soc/soc-core.c index 462e635dfc74..ad381138fc2e 100644 --- a/trunk/sound/soc/soc-core.c +++ b/trunk/sound/soc/soc-core.c @@ -4,7 +4,8 @@ * Copyright 2005 Wolfson Microelectronics PLC. * Copyright 2005 Openedhand Ltd. * - * Author: Liam Girdwood + * Author: Liam Girdwood + * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com * with code, comments and ideas from :- * Richard Purdie * @@ -1885,7 +1886,7 @@ module_init(snd_soc_init); module_exit(snd_soc_exit); /* Module information */ -MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk"); +MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com"); MODULE_DESCRIPTION("ALSA SoC Core"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:soc-audio"); diff --git a/trunk/sound/soc/soc-dapm.c b/trunk/sound/soc/soc-dapm.c index efbd0b37810a..9ca9c08610fa 100644 --- a/trunk/sound/soc/soc-dapm.c +++ b/trunk/sound/soc/soc-dapm.c @@ -2,7 +2,8 @@ * soc-dapm.c -- ALSA SoC Dynamic Audio Power Management * * Copyright 2005 Wolfson Microelectronics PLC. - * Author: Liam Girdwood + * Author: Liam Girdwood + * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.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 @@ -1482,26 +1483,6 @@ 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 @@ -1540,6 +1521,6 @@ void snd_soc_dapm_free(struct snd_soc_device *socdev) EXPORT_SYMBOL_GPL(snd_soc_dapm_free); /* Module information */ -MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk"); +MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com"); MODULE_DESCRIPTION("Dynamic Audio Power Management core for ALSA SoC"); MODULE_LICENSE("GPL");